【问题标题】:LIKE with integers, in SQLLIKE 与整数,在 SQL
【发布时间】:2011-08-10 22:16:11
【问题描述】:

我可以用LIKE 替换= 语句来代替整数吗?

例如。以下是同一件事:

select * from FOOS where FOOID like 2    
// and 
select * from FOOS where FOOID = 2

我更喜欢使用 LIKE 而不是 =,因为当我没有 FOOID 过滤器时,我可以使用 %...

SQL Server 2005。

编辑 1 @Martin

【问题讨论】:

  • 您对LIKE 2 的结果有何期望?? INT 值要么完全匹配,要么不完全匹配 - INT 没有 LIKE 功能,真的....
  • @marc_s:它与没有通配符的字符串完全相同:完全匹配。 @op 正在尝试重新发明一种过滤“这个或任何东西”的解决方案:stackoverflow.com/questions/5754619/sql-where-myid-any
  • 如果您确实走这条路,请务必明确强制转换 FOOID,以便其他人查看您的代码时可以清楚地看到该行为。
  • 在这种情况下,您的计划执行百分比不准确,因为您在其中有 INSERT 语句并且它会扭曲结果。 INSERT 语句比任何一个 SELECT 语句都要昂贵得多。只需自己检查两个 SELECT 语句的执行计划即可。
  • @Martin 抱歉,我正在向@serhio 讲话。他在问题中发布了一张图片,显示两个选择的绩效百分比相同。

标签: sql sql-server sql-server-2005 sql-like


【解决方案1】:

使用 NULL 作为通配符条件的参数值,而不是 %

select * from table1 where (@DepartmentID IS NULL OR deptNo = @DepartmentID)

【讨论】:

    【解决方案2】:

    这是一个迟到的评论,但我想也许其他人正在寻找同样的东西,所以我能够找到解决方案,我想我应该在这里分享它:)

    问题的简短描述: 我遇到的问题是能够使用通配符敌人整数数据类型。我正在使用 SQL Server,所以我的语法适用于 SQL Server。我有一列显示部门编号,我想从我的页面从下拉菜单中传递一个变量。还有一个“全部”选项,在这种情况下,我想将“%”作为参数传递。我正在使用这个:

    select * from table1 where deptNo Like @DepartmentID
    

    当我传递一个数字时它有效,但不适用于 %,因为 sql server 将 @DepartmentID 隐式转换为 int(因为我的 deptNo 是 int 类型)

    所以我选择了 deptNo 并解决了这个问题:

    select * from table1 where CAST(deptNo AS varchar(2)) Like @DepartmentID
    

    当我传递一个像 4 这样的数字和传递% 时,这个都适用。

    【讨论】:

    • 请记住,将函数应用于这样的列很可能会使您的查询非sargable
    • 这是我能想到的唯一解决方案。有没有更好的解决方案可以让您使用 sargable 查询?
    • 不确定。在这种情况下,也许不可能提出一个 sargable 查询,因为类型转换,无论是显式的还是隐式的,都不可避免地会涉及到。
    【解决方案3】:

    使用CASE 语句将输入字符串转换为整数。将通配符 % 转换为 NULL。与将整个 int 列隐式转换为字符串相比,这将提供更好的性能。

    CREATE PROCEDURE GetFoos(@fooIdOrWildcard varchar(100))
    AS
    BEGIN
        DECLARE @fooId int
    
        SET @fooId =
            CASE
                -- Case 1 - Wildcard 
                WHEN @fooIdOrWildcard = '%'
                    THEN NULL
                -- Case 2 - Integer
                WHEN LEN(@fooIdOrWildcard) BETWEEN 1 AND 9
                AND @fooIdOrWildcard NOT LIKE '%[^0-9]%'
                    THEN CAST(@fooIdOrWildcard AS int)
                -- Case 3 - Invalid input
                ELSE 0
            END
    
        SELECT FooId, Name
        FROM dbo.Foos
        WHERE FooId BETWEEN COALESCE(@fooId, 1) AND COALESCE(@fooId, 2147483647)
    END
    

    【讨论】:

    • WHERE (FooId = @fooId OR @fooId IS NULL) 仍然有问题。见sommarskog.se/dyn-search-2005.html#OR_ISNULL
    • @Martin 很好的建议。我已更新查询以使用 BETWEEN-COALESCE 而不是 OR-IS-NULL。
    • 是的。看到了,并且已经 +1 了。该方法应该可以解决问题。
    【解决方案4】:
    select * from FOOS where FOOID like 2
    

    应该避免,因为它会导致双方都被隐式转换为varchar,并且意味着不能使用索引来满足查询。

    CREATE  TABLE #FOOS
    (
    FOOID INT PRIMARY KEY,
    Filler CHAR(1000)
    )
    INSERT INTO #FOOS(FOOID)
    SELECT DISTINCT number 
    FROM master..spt_values
    
    
    SELECT * FROM #FOOS WHERE FOOID LIKE 2
    
    SELECT * FROM #FOOS WHERE FOOID = 2
    
    DROP TABLE #FOOS
    

    计划(注意估计费用)

    查看成本差异的另一种方法是添加SET STATISTICS IO ON

    你看到第一个版本返回类似

    Table '#FOOS__000000000015'. Scan count 1, logical reads 310
    

    第二版回归

    Table '#FOOS__000000000015'. Scan count 0, logical reads 2
    

    这是因为在该索引上查找所需的读取与索引深度成正比,而扫描所需的读取与索引中的页数成正比。表越大,这两个数字之间的差异就会越大。您可以通过运行以下命令来查看这两个数字。

    SELECT index_depth, page_count
    FROM
    sys.dm_db_index_physical_stats (2,object_id('tempdb..#FOOS'), DEFAULT,DEFAULT, DEFAULT)
    WHERE object_id = object_id('tempdb..#FOOS') /*In case it hasn't been created yet*/
    

    【讨论】:

    • 也就是说,你不建议使用like来代替=
    • @serhio - 绝对不是因为它需要扫描所有行,而不是在 id 列上直接进行索引查找。
    • @serhio - 看起来您正在运行“估计的”执行计划。尝试“实际”执行计划。生成估计计划时,临时表尚不存在,因此没有统计信息,SQL Server 将假定该表仅包含 1 行。自己创建 #temp 表然后运行 ​​2 个语句可能更好。
    • @serhio - 我没有在这台机器上使用 SQL Server 2005,所以我不确定它的估计成本是否存在一些奇怪的问题,或者你生成计划的方式是否存在问题(您是否先填充表格?)但可以向您保证,查找比扫描更有效。我将编辑我的答案以展示另一种可以证明这一点的方式。
    • 主题图更新重装英文版SQL Studio :) + 实际路径)
    【解决方案5】:

    是的,你可以使用它:

    SELECT  *
    FROM    FOOS
    WHERE   FOOID like 2   
    

    SELECT  *
    FROM    FOOS
    WHERE   FOOID like '%'  
    

    整数将被隐式转换为字符串。

    请注意,这些条件都不是 sargable,即。 e.能够在fooid 上使用索引。这将始终导致全表扫描(或对fooid 的全索引扫描)。

    【讨论】:

    • 也就是说,你同意我给出的例子中的SQL是等价的
    • @serhio:从逻辑上讲,是的,它们是等价的。但是,它们的执行计划会有所不同:如果fooid 是整数,则第一个将永远无法使用fooid 上的索引,并且始终必须处理表中的所有记录,而第二个可能使用索引。
    猜你喜欢
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 2022-09-29
    • 1970-01-01
    • 2021-04-12
    相关资源
    最近更新 更多