【问题标题】:MySQL variable format for a "NOT IN" list of values“NOT IN”值列表的 MySQL 变量格式
【发布时间】:2012-08-11 01:26:27
【问题描述】:

疯狂地尝试在类型查询中设置变量:

SET @idcamposexcluidos='817,803,495';

这样我就可以用它了

WHERE id_campo not in (@idcamposexcluidos)

我尝试以不同的格式定义变量,但没有成功,似乎没有找到上述的具体示例:

SET @idcamposexcluidos='(817,803,495)';
...
WHERE id_campo not in @idcamposexcluidos


SET @idcamposexcluidos=817,803,495;

没有成功。它要么返回错误,要么忽略值。

【问题讨论】:

  • 你不能这样使用in。您需要单独的变量或使用动态 SQL。
  • FIND_IN_SETLIKE 适用于小桌子。但他们表现不佳,因为他们必须查看每一行。大多数语言都没有简单的方法(如果有的话)来构造更快的IN(...) 子句,它可以使用索引。

标签: mysql sql in-clause


【解决方案1】:

你不能像那样使用IN 子句。它会在您的 IN 子句中编译成 single 字符串。但是IN 子句需要单独的 值。

WHERE id_campo not in (@idcamposexcluidos)

编译成

WHERE id_campo not in ('817,803,495')

但应该是的

WHERE id_campo not in ('817','803','495')

要克服这个问题,可以使用动态 SQL 或在 MySQL 中使用FIND_IN_SET

SET @idcamposexcluidos='817,803,495';
...
WHERE FIND_IN_SET(id_campo, @idcamposexcluidos) = 0

但是使用像FIND_IN_SET()这样的函数不能使用索引。

【讨论】:

  • 太棒了!起初我认为这行不通,因为我既忽略了又不熟悉 FIND_IN_SET 方法。我担心“80”会因为“803”而产生误报,但效果很好!
  • 如果你喜欢使用 IN 子句而不是 NOT IN,只需将 '= 0' 替换为 '> 0' --> WHERE FIND_IN_SET(id_campo, @idcamposexcluidos) > 0
  • @Bruno 你也可以这样做:WHERE FIND_IN_SET(id_campo, @idcamposexcluidos)。也就是说,将FIND_IN_SET 的结果视为布尔值。 NOT IN 等价表达式的答案也可以这样写:WHERE NOT FIND_IN_SET(id_campo, @idcamposexcluidos)
  • 关于此的重要说明:数据库引擎似乎不够聪明,无法优化查询。 EXPLAIN EXTENDED SELECT * FROM users WHERE FIND_IN_SET(user_id, @userlist) ==> 全表扫描(在大表上非常慢)。 EXPLAIN EXTENDED SELECT * FROM users WHERE user_id IN (1, 2, 3, 4) ==> 使用主键索引(非常快)。 (在 MySQL 5.6/innodb 上测试。)
  • @Kip:使用函数通常会阻止使用索引。
【解决方案2】:

如果你使用mysql > 5.1,你可以使用:

CREATE TYPE lista as (
    clave int4,
    valor int4
);

CREATE OR REPLACE FUNCTION test(IN vArray lista[])
...

   WHERE FIND_IN_SET(id_campo, vArray)
...

在其他情况下,您可以使用技巧:

WHERE id_campo IN ( SELECT 817 as valor UNION ALL 
                SELECT 803 as valor UNION ALL
                    SELECT 495 as valor)

【讨论】:

    【解决方案3】:

    通过使用CONCAT()、一个管道分隔符(而不是逗号)和一些“反向逻辑”,您可以在NOT IN 列表中使用一个变量,但改为使用NOT LIKE

    例子:

    SET @idcamposexcluidos = '|817|803|495|';
    
    SELECT
        *
    FROM
        your_table
    WHERE
        @idcamposexcluidos NOT LIKE CONCAT('%|', id_campo, '|%');
    

    这应该适用于字符串和数字列。

    【讨论】:

    • 似乎也可以,但不确定为什么我会在同一个搜索中获得更多行!任何案例 juergen d 解决方案都很好。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2012-01-11
    • 2022-07-04
    • 1970-01-01
    相关资源
    最近更新 更多