代码之家  ›  专栏  ›  技术社区  ›  cdonner

t-sql isnumeric()和linq to sql

  •  7
  • cdonner  · 技术社区  · 15 年前

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

    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 回复  |  直到 6 年前
        1
  •  12
  •   Ruben    15 年前

    虽然 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;
    
        2
  •  11
  •   Ahmad Mageed    14 年前

    你可以利用 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.Parse 关于SQL。

        3
  •  1
  •   Sнаđошƒаӽ    6 年前

    正如您所说,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:更改数据库架构:-)

        4
  •  0
  •   Paul G    14 年前

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

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