8

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

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', ''))

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

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

4

4 回答 4

13

虽然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;
于 2010-02-24T21:35:53.033 回答
11

您可以ISNUMERIC通过向 DataContext 的部分类添加方法来使用该函数。这类似于使用 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”文本,以避免获取列名的第二个查询。

编辑:正如评论中提到的,这种方法的缺点是排序是在文本而不是数值上完成的,并且目前没有Int32.ParseSQL 的翻译。

于 2010-02-24T22:47:12.687 回答
1

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

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

于 2010-02-24T21:39:01.340 回答
0

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

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

于 2010-06-09T23:44:37.427 回答