T-SQL IsNumeric()和Linq-to-SQL

问题描述 投票:7回答:4

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

EU999999('9'是任意数字)

select max(col)将返回类似'EUZ ...'的内容,例如我想要排除的内容。以下查询可以解决问题,但我无法通过Linq-to-SQL生成此问题。似乎没有SQL Server中的isnumeric()函数的转换。

select max(col) from table where col like 'EU%' 
    and 1=isnumeric(replace(col, 'EU', ''))

编写数据库函数,存储过程或其他任何性质的东西都在我的首选解决方案的列表中,因为这个表是我的应用程序的核心,我不能轻易地用其他东西替换表对象。

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

sql-server linq-to-sql tsql isnumeric
4个回答
12
投票

虽然缺少ISNUMERIC,但你总是可以尝试几乎等效的NOT LIKE '%[^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;

11
投票

您可以通过向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”文本以避免获取列名称的第二个查询。

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


1
投票

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

选项1:您可以通过将LINQ to SQL与LINQ to Objects混合来实现这一点,但是当您拥有一个大型数据库时,不要期望出色的性能:

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:更改数据库架构:-)


0
投票

我的建议是回退到内联SQL并使用DataContext.ExecuteQuery()方法。您将使用您在开头发布的SQL查询。

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

© www.soinside.com 2019 - 2024. All rights reserved.