【问题标题】:Peculiarities of MySQL's IN clauseMySQL IN 子句的特点
【发布时间】:2011-08-09 02:32:17
【问题描述】:

我刚刚使用 MySQL 的 IN 解决了​​一个有趣的问题,但我不知道这个“技巧”叫什么。

在我的设计中,我需要过滤掉不需要特定技能或满足技能名称和技能级别的行。这是解决方案:

SELECT * FROM table WHERE
    skillname = "" OR
    (skillname, skilllevel) IN (
        SELECT name, level FROM skills WHERE user="Mikhail"
    )

我不知道expr IN (value,...),因为dev.mysql.comexprvalue都可以是多列。

这叫什么,还有更多类似的快捷方式吗?
更重要的是 - 有没有办法将此查询转换为将skilllevel 匹配为“大于或等于”?


解决方案根据@yokoloko(虽然他不会承认)

SELECT * FROM t1 WHERE
    skillname = "" OR
    skillname IN (
        SELECT name FROM skills WHERE user="Mikhail" AND level >= t1.skilllevel
    )

【问题讨论】:

    标签: mysql optimization


    【解决方案1】:

    抱歉,IN 谓词总是比较 相等 的值,不大于或等于。

    我是这样写的:

    SELECT table.* 
    FROM table WHERE skillname = ''
    UNION ALL
    SELECT table.* 
    FROM table JOIN skills 
      ON table.skillname = skills.name AND table.skilllevel >= skills.level
    WHERE skills.user = 'Mikhail'
    

    至于查询的术语,@guide 指出您运行了 row 子查询,并使用 row constructor 语法将其与文字行进行了比较。 SQL 允许您使用列、表达式或值创建匿名行,并在某些情况下使用它们,例如与具有兼容列数的另一行进行比较。我称之为行比较

    你也可以在连接条件中使用它,但如果你想对一列进行相等比较,对另一列进行不等比较,那就很不清楚了:

    SELECT table.* 
    FROM table JOIN skills 
      ON (table.skillname, table.skilllevel) >= (skills.name, skills.level)
    WHERE skills.user = 'Mikhail'
    

    上面可能不会做你想要的。示例:

    SELECT (1,2) = (1,2);   -- returns true (i.e. 1 in MySQL)
    
    SELECT (1,2) >= (1,2);  -- returns true
    
    SELECT (1,3) >= (1,2);  -- returns true
    
    SELECT (1,2) >= (1,3);  -- returns false
    
    SELECT (2,3) >= (1,2);  -- returns true
    
    SELECT (1,3) >= (2,2);  -- returns false
    

    相同的比较运算符应用于这些行中的所有列。但它也会短路(不像AND):

    SELECT (2,3) >= (1,4);  -- returns true
    

    2 大于 1,但 3 不大于 4。令人困惑?考虑一个按字母顺序排列的例子:

    SELECT ('Smith', 'Agent') >= ('Anderson', 'Thomas'); -- returns true
    

    史密斯比安德森大,但特工不比托马斯大。不过,我们知道如何在电话簿中对这两个名字进行排序。

    所有这一切的重点是,如果您想更好地控制比较,则需要编写完整的布尔表达式。

    【讨论】:

      【解决方案2】:

      那叫row subquery

      行子查询是返回单行的子查询变体,并且可以 因此返回多个列值。

      【讨论】:

      • 行子查询当然不是原始的。 (不能编辑少于 6 个字符)
      【解决方案3】:

      我不知道它是怎么称呼的,但如果我理解得很好,你可以做这样的事情来获得大于:

      SELECT * FROM table t1 WHERE
          skillname = "" OR
          (skillname, skilllevel) IN (
              SELECT name, level FROM skills s WHERE user="Mikhail" and t1.skilllevel >= s.level
          )
      

      但是不知道优化的好不好。

      【讨论】:

      • 有道理,虽然因为 IN 比较相等,仍然行不通
      • 我相信如果你只是从 SELECT 中删除 INlevel 左侧的 skilllevel - 整个查询将起作用,因为如果级别不会返回 name不匹配
      • 是的,但那时你不会知道技能水平,显然你需要它。
      • 子查询 WHERE 子句仍然可以访问 t1.skilllevel,因此 >= 将正常工作
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-20
      • 2017-06-15
      • 2015-04-02
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      相关资源
      最近更新 更多