使用 CONCAT 函数或类似函数筛选查询

Filter a query using the CONCAT function or similar

提问人:Blazer1984 提问时间:4/13/2022 最后编辑:Dale KBlazer1984 更新时间:4/13/2022 访问量:476

问:

我有一个查询,该查询是根据订单号列表筛选的。订单号的实际归档长度为 9 个字符 (char)。但是,有时,最终用户从中获取订单号的系统会在此订单号的开头生成一个额外的 0 或单个字母字符。我正在尝试使用现有的 SQL 来解决这个问题,尽管它正在运行,但它需要成倍的时间(有时甚至不会运行)。

我下面采用的方法是否是解释这些差异的最佳方法?

订单号字段示例:

066005485, 066005612

可能输入的内容示例,我需要说明:

0066005485, A066005612

这是我尝试过的似乎不起作用或至少非常慢的方法:

SELECT S.order_no AS 'contract_no',
       S.SIZE_INDEX AS 'technical_index',
       S.open_qty AS 'contract_open_qty',
       S.order_qty AS 'contract_order_qty',
       E.excess,
       (S.order_qty - E.excess) AS 'new_contract_size_qty'

FROM   EXCESS E 
JOIN   SIM S ON RIGHT(E.GPS_CONTRACT_NUMBER,9) = S.order_no AND E.[AFS TECH INDEX] = S.size_index

WHERE S.order_no IN ('0066003816','0066003817','0066005485','0066005612','0066005390','0066005616','0066005617','A066005969','A066005970','0066005952','0066005798','0066006673','0066005802','0066006196','0066006197','0066006199','0066006205','0066006697')

OR   CONCAT('0',S.order_no) IN ('0066003816','0066003817','0066005485','0066005612','0066005390','0066005616','0066005617','A066005969','A066005970','0066005952','0066005798','0066006673','0066005802','0066006196','0066006197','0066006199','0066006205','0066006697')

ORDER BY S.order_no, 
         S.size_index


对可能更好或我错过的东西有什么想法吗?

SQL 服务器

评论

3赞 Dale K 4/13/2022
您希望不惜一切代价避免转换列数据,因为一旦转换,SQL Server 就无法使用索引。相反,您需要转换传入的标准。
0赞 Thom A 4/13/2022
您的子句也是不可 SARGable 的,因为 .您需要使用它的事实意味着您的列用于在单个值中包含多个数据项。ONRIGHT
0赞 Thom A 4/13/2022
旁注:不要使用单引号 () 作为别名。单引号用于文本字符串,而不是分隔标识对象名称。它们只有在你定义它们时才有效,在其他地方不起作用; 不会按别名为 的列排序,而是按文字排序(因此实际上根本不会排序)。此外,一些带有文本字符串别名的语法也被弃用。坚持使用不需要分隔标识的对象和别名,如果必须分隔标识它们,请使用 T-SQL 标识符、括号 () 或 ANSI-SQL 的双引号 ()。'ORDER BY 'value''value'varchar'value'[]"
0赞 Stu 4/13/2022
在联接和where conditions中使用“和”等函数会强制 SQL Server 每次扫描表/索引中的所有行。想象一下,一排有 100 个盒子,每个盒子外面都有一个数字,我让你找到上面有数字 10 的盒子——很容易。现在,如果数字在关闭的框内,则必须依次打开每个框并查看 - 这就是您的函数强制 SQL Server 执行的操作。right()concat()
0赞 EdmCoff 4/13/2022
如上所述,删除输入的第一个字符可能比将其添加到列中更有效。例如: 涵盖这两种情况,并可以在order_no上使用索引。concatWHERE order_no IN ('0066003816', '066003816')

答:

1赞 Chris Maurer 4/13/2022 #1

对于需要正确功能的讨厌的连接,我无能为力。如果您对数据库设计者有任何影响,那么在将该键 (E.GPS_CONTRACT_NUMBER) 放入表之前将其清理干净,或者让他们添加另一个已经执行 RIGHT(E.GPS_CONTRACT_NUMBER,9) 并可以创建索引的字段,这可能会很有成效。

但是,您肯定可以采取一些措施来删除 concat 函数计算并利用S.order_no上的任何索引。我注意到您的 Where 子句看起来像 order_no IN listofvals 或 Concat('0', order_no) IN samelistofvals 。因此,与其在 order_no 上添加一个零,不如从 IN 列表中的所有内容中删除一个零。

Where order_no IN ('0066003816','0066003817','0066005485','0066005612','0066005390','0066005616','0066005617','A066005969','A066005970','0066005952','0066005798','0066006673','0066005802','0066006196','0066006197','0066006199','0066006205','0066006697', 
'066003816','066003817','066005485','066005612','066005390','066005616','066005617','066005952','066005798','066006673','066005802','066006196','066006197','066006199','066006205','066006697')

请注意,IN-list 在两行上,第二行只是重复的第一行,删除了前导 0,并且完全删除了任何以“A”开头的条目。这简化了 Where 子句,并允许使用索引(如果存在)。

0赞 lemon 4/13/2022 #2

如果效率问题出在子句中(不考虑操作),为了改善这种情况,可以尝试使用“伪正则表达式”模式匹配方式,如下:WHEREJOINLIKE

WHERE 
    S.order_no LIKE '[A0]06600%' 
OR 
    S.order_no LIKE '06600%'

警告:此模式还将匹配以其他数字结尾的字符串(例如 8648)。

它对你有用吗?