Sql server T-SQL IsNumeric()和Linq到SQL

Sql server T-SQL IsNumeric()和Linq到SQL,sql-server,linq-to-sql,tsql,isnumeric,Sql Server,Linq To Sql,Tsql,Isnumeric,我需要从数据库中找到满足某种格式约定的最高值。具体地说,我想找到 EU999999('9'为任意数字) select max(col)将返回类似于“EUZ…”的内容,例如我要排除的内容。 下面的查询实现了这一点,但我无法通过LINQtoSQL生成此查询。SQL Server中的isnumeric()函数似乎没有翻译 select max(col) from table where col like 'EU%' and 1=isnumeric(replace(col, 'EU', '')

我需要从数据库中找到满足某种格式约定的最高值。具体地说,我想找到

EU999999('9'为任意数字)

select max(col)将返回类似于“EUZ…”的内容,例如我要排除的内容。 下面的查询实现了这一点,但我无法通过LINQtoSQL生成此查询。SQL Server中的isnumeric()函数似乎没有翻译

select max(col) from table where col like 'EU%' 
    and 1=isnumeric(replace(col, 'EU', ''))
编写数据库函数、存储过程或其他类似性质的东西是我首选的解决方案,因为这个表是我的应用程序的核心,我无法轻松地用其他东西替换表对象


下一个最佳解决方案是什么?

尽管缺少
ISNUMERIC
,但您始终可以尝试类似于“%$0-9]]的近似等效
,即字符串中没有非数字,或者字符串为空或仅由数字组成:

from x in table 
where SqlMethods.Like(x.col, 'EU[0-9]%') // starts with EU and at least one digit
  && !SqlMethods.Like(x.col, '__%[^0-9]%') // and no non-digits
select x;
当然,如果您知道位数是固定的,可以简化为

from x in table 
where SqlMethods.Like(x.col, 'EU[0-9][0-9][0-9][0-9][0-9][0-9]')
select x;

正如您所说,IsNumeric没有从LINQ到SQL的转换。有几个选项,您已经写下了数据库函数和存储过程。我想再加两个

选项1:您可以通过混合使用LINQ to SQL和LINQ to对象来实现这一点,但是当您拥有一个大型数据库时,不要期望有很好的性能:

var cols = (from c in db.Table where c.StartsWith("EU") select c).ToList();
var stripped = from c in cols select int.Parse(c.Replace("EU", ""));
var max = stripped.Max();

选项2:更改数据库架构:-)

您可以通过向DataContext的分部类添加方法来使用
ISNUMERIC
函数。这类似于使用UDF

在DataContext的分部类中添加以下内容:

partial class MyDataContext
{
    [Function(Name = "ISNUMERIC", IsComposable = true)]
    public int IsNumeric(string input)
    {
        throw new NotImplementedException(); // this won't get called
    }
}
然后您的代码将以以下方式使用它:

var query = dc.TableName
              .Select(p => new { p.Col, ReplacedText = p.Col.Replace("EU", "") })
              .Where(p => SqlMethods.Like(p.Col, "EU%")
                        && dc.IsNumeric(p.ReplacedText) == 1)
              .OrderByDescending(p => p.ReplacedText)
              .First()
              .Col;

Console.WriteLine(query);
或者您可以使用MAX:

var query = dc.TableName
              .Select(p => new { p.Col, ReplacedText = p.Col.Replace("EU", "") })
              .Where(p => SqlMethods.Like(p.Col, "EU%")
                  && dc.IsNumeric(p.ReplacedText) == 1);

var result = query.Where(p => p.ReplacedText == query.Max(p => p.ReplacedText))
                  .First()
                  .Col;

Console.WriteLine("Max: {0}, Result: {1}", max, result);
根据您的最终目标,可能会在
max
变量处停止,并在其前面加上“EU”文本,以避免第二次查询获取列名


EDIT:如评论中所述,这种方法的缺点是排序是在文本上而不是在数值上进行的,并且目前没有对SQL上的
Int32.Parse
进行翻译。

我的建议是回到行内SQL并使用DataContext.ExecuteQuery()方法。您将使用开始时发布的SQL查询


这就是我在类似情况下所做的。当然,这并不理想,因为缺乏类型检查和可能的语法错误,但只需确保它包含在任何单元测试中。并非所有可能的查询都包含在Linq语法中,因此首先存在ExecuteQuery

我喜欢你的建议,我会接受它,但我的前缀(和长度)不是一个常数,不幸的是,因此我必须动态生成表达式。我不喜欢,我正在考虑改变模式的方法,这样我就可以解决这个问题。使用类似于
的,前面没有通配符的优点之一是,这非常方便索引(可以对索引进行范围检查)。在变长表达式上,这是一个非常聪明的替代IsNumeric的方法。在字符串中的任何位置查找非数字字符。谢谢你的提示!不过,+1表示建议更改我的模式。+1。我很惊讶这是可能的。不要忘记OrderByDescending(p=>p.ReplacedText)是基于文本的(ReplacedText是字符串/varchar),因此这可能不会产生正确的结果。排序前必须将其转换为整数。@Steven谢谢,对于简单函数来说,这是一个很好的解决方法。关于订单你是对的。不幸的是,没有解决方法,而且
Int32。Parse
没有转换为SQL,因此对于数字排序,真正的UDF/SPROC是最好的。同样,这是我在一段时间内看到的最巧妙的事情之一。一个小缺点是,如果使用Convert.ToInt32,它总是被计算的。您可以绕过这个问题:(db.IsNumeric(p.AddressPostCode)==1?(int?)Convert.ToInt32(p.AddressPostCode):null)