【问题标题】:MYSQL: Can you pull results that match like 3 out of 4 expressions?MYSQL:你能提取匹配 4 个表达式中的 3 个的结果吗?
【发布时间】:2009-04-18 04:33:10
【问题描述】:

假设我有这样的查询:

SELECT * FROM my_table WHERE name = "john doe" AND phone = "8183321234" AND email = "johndoe@yahoo.com" AND address = "330 some lane";

但是假设我只需要 4 个中的 3 个来匹配,我知道我可以编写一个包含多个 OR 的很长的查询,但我想知道是否有这样的功能?

谢谢。

【问题讨论】:

    标签: mysql


    【解决方案1】:
    SELECT
      * 
    FROM 
      my_table 
    WHERE 
      CASE WHEN name = "john doe"           THEN 1 ELSE 0 END +
      CASE WHEN phone = "8183321234"        THEN 1 ELSE 0 END +
      CASE WHEN email = "johndoe@yahoo.com" THEN 1 ELSE 0 END +
      CASE WHEN address = "330 some lane"   THEN 1 ELSE 0 END
      >= 3;
    

    旁注:这很可能不会有效地使用索引。另一方面,无论如何,这些列很可能没有索引。

    【讨论】:

    • 我认为只需对比较表达式求和就足够了,因为它们本身总是返回 0 或 1:name="john doe" + phone="12345" + email="john.doe@example.com" + address="123 some lane" >= 3
    • 是的,我猜是在 MySQL 上做的。尽管如此,我更喜欢明确性,并且比较操作不一定会在其他系统上返回数值。
    • 是的,我想我应该说'神圣的雷鸣般的 sesquipedalian 冗长,蝙蝠侠'。但是,如果有人不理解布尔表达式的数值计算,他们应该能够从我的示例中快速推断出来。 :)
    • @Tomalak: "sesquipedialian" = "1,5 feet long",来自 Horace 的“Ars Poetica”
    • 我的一个朋友用它来无情地嘲弄我会使用的某些词组。我喜欢它,当然。就像我经常说的:永远不要在一个小的词位足够的情况下使用一个大词。
    【解决方案2】:

    太复杂了,蝙蝠侠。

    SELECT * 
    FROM my_table 
    WHERE (
        (name = "john doe") +
        (phone = "8183321234") +
        (email = "johndoe@yahoo.com") +
        (address = "330 some lane")
    ) >= 3;
    

    【讨论】:

    • 蝙蝠侠评论+1。我不确定这是否有效,但确实有效,无论如何+1 是当之无愧的,因为那非常整洁。 :)
    • 非常感谢。当然它有效;如果我能提供帮助,我绝不会在没有测试的情况下发布 SQL。
    • 我还是 SQL 新手,但我不明白该查询是如何完成它的工作的。
    • MySQL 没有与整数不同的“布尔值”概念。即使是大多数确实有这种概念的语言也允许在数字上下文中评估布尔值,产生 0 或 1 个整数。
    • 谢谢,我知道您可以将 1 或 0 用作布尔值,但我不知道您可以将布尔值用作 1 或 0(如果有意义的话)。
    【解决方案3】:

    使用索引也是一样:

    SELECT  *
    FROM    (
            SELECT  id
            FROM    (
                    SELECT  id
                    FROM    mytable _name
                    WHERE   name = 'john doe'
                    UNION ALL
                    SELECT  id
                    FROM    mytable _name
                    WHERE   phone = '8183321234'
                    UNION ALL
                    SELECT  id
                    FROM    mytable _name
                    WHERE   email = "johndoe@yahoo.com"
                    UNION ALL
                    SELECT  id
                    FROM    mytable _name
                    WHERE   address = '330 some lane'
                    ) q
            GROUP BY 
                    id
            HAVING
                    COUNT(*) >= 3
            ) di, mytable t
    WHERE   t.id = di.id
    

    有关性能详情,请参阅the entry in my blog

    【讨论】:

    • 繁琐的任务,我知道这个投票率很高的业务。 :-D
    • OBTW:您能否说明 CASE WHEN 谓词中是否使用了索引?谢谢。
    • 当然。不使用索引。我将在我的博客中就这个问题发表今天的文章,详情请参见此处。
    【解决方案4】:

    我喜欢 IF 结构:

    SELECT * FROM my_table
    WHERE
    (    IF(name    = 'john doe', 1, 0) +
         IF(phone   = '8183311234', 1, 0) +
         IF(email   = 'johndoe@yahoo.com', 1, 0) +
         IF(address = '330 some lane', 1, 0)
    ) >= 3
    

    【讨论】:

      【解决方案5】:

      稍微修改 Tomalak 的查询,以便它使用索引(如果存在)。虽然除非每个字段都有索引,否则无论如何都会发生全表扫描。

      SELECT
      *, 
      (
          IF(name="john doe", 1, 0) +
          IF(phone = "8183321234", 1, 0) +
          IF(email = "johndoe@yahoo.com", 1, 0) +
          IF(address = "330 some lane", 1, 0) 
      ) as matchCount
      FROM my_table 
      WHERE 
          name = "john doe" OR 
          phone = "8183321234" OR 
          email = "johndoe@yahoo.com" OR 
          address = "330 some lane"
      HAVING matchCount >= 3
      

      【讨论】:

      • 您需要将代码示例缩进 4 个空格以使其显示良好。我为你做了这个改变,希望你不要介意。 :)
      • Mysql 索引合并性能比 UNION ALL 差。见这里:explainextended.com/2009/03/07/selecting-friends
      • @Paolo 在这里输入代码示例时如何缩进?
      • @John Isaacks:选择一段代码,然后按编辑字段上方的 0100101 按钮。所选代码将缩进 4 个空格。
      • @John Isaacks:对于复制/粘贴代码示例,它有助于预先在文本编辑器中用空格替换所有制表符,因为制表符和空格结合起来往往会破坏布局。
      猜你喜欢
      • 2011-09-28
      • 1970-01-01
      • 2013-12-18
      • 2019-06-19
      • 2012-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-02
      相关资源
      最近更新 更多