我需要从数据库中找到满足某种格式约定的最高值。具体来说,我想找到看起来最高的价值
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', ''))
编写数据库函数,存储过程或其他任何性质的东西都在我的首选解决方案的列表中,因为这个表是我的应用程序的核心,我不能轻易地用其他东西替换表对象。
什么是下一个最佳解决方案?
虽然缺少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;
您可以通过向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
的翻译。
正如您所说,从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:更改数据库架构:-)
我的建议是回退到内联SQL并使用DataContext.ExecuteQuery()方法。您将使用您在开头发布的SQL查询。
这就是我在类似情况下所做的。由于缺乏类型检查和可能的语法错误,并不是理想的,只是确保它包含在任何单元测试中。并非Linq语法涵盖了所有可能的查询,因此首先存在ExecuteQuery。