【问题标题】:How to execute a SELECT on a table with a list of composite keys?如何在具有复合键列表的表上执行 SELECT?
【发布时间】:2011-12-13 12:06:59
【问题描述】:

如果我有一个包含类似列的表格

ID1 ID2 VAL1 VAL2

其中 ID1,ID2 构成主键索引。

如何针对特定 ID1、ID2 值执行任何 SQL 语句?

示例:我的表包含 PK (1,1) (1,2) (2,4) (2,1) (3,1) (3,2) (3,5) 的记录

我只想选择具有 (1,1) (1,2) (3,5) (3,2) 的记录

一个 SELECT 查询

SELECT * FROM tbl1 WHERE ID1 IN (1,3) AND ID2 IN (1,2,5)

将产生不希望的结果:(3,1)。那么最好的方法是什么?

我正在寻找 SQL 的整体答案,但如果它依赖于 DBMS,我想知道如何在 PostgreSQL 和 MySQL 中这样做。

【问题讨论】:

    标签: mysql sql postgresql


    【解决方案1】:

    您可以使用andor 做到这一点:

    SELECT  * 
    FROM    tbl1
    WHERE   ID1 = 1 AND ID2 = 1 OR
            ID1 = 1 AND ID2 = 2 OR
            ID1 = 3 AND ID2 = 5 OR
            ID1 = 2 AND ID2 = 2
    

    【讨论】:

    • 想必这是唯一的办法吧?它仍然会使用主键索引吗?在处理复合键时,SQL 似乎突然出现了低效的语言障碍。
    【解决方案2】:

    MySQL 和 PostgreSQL 都支持IN 中的元组,如下所示。

    SELECT * 
    FROM tbl1
    WHERE (ID1,ID2) IN ((1,1) (1,2) (2,4) (2,1) (3,1) (3,2) (3,5));
    

    【讨论】:

    • 这就是我要找的。 PostgreSQL 也支持这种语法。但是我想知道它是否遵守最左边的前缀规则来利用主键索引。
    • @RonaldChan - 你必须看看解释计划。无法想象该构造会对相应的优化器造成任何特定问题,但不确定。
    • 谢谢。至少在 Postgres 中似乎是这样。
    • @RonaldChan:主键在(ID1, ID) 上创建了一个多列。只要两个列都包含在条件中,索引将同样有效地使用。我写的更多,加上链接here
    • @ErwinBrandstetter - 链接中的答案很好。我错过了第一轮!
    【解决方案3】:

    这可能是满足您要求的最紧凑的方式:

    SELECT *
    FROM tbl1
    WHERE (ID1 = 1 AND (ID2 = 1 OR ID2 = 2))
       OR (ID1 = 3 AND (ID2 = 5 OR ID2 = 2));
    

    【讨论】:

      【解决方案4】:
      SELECT * FROM tbl1 WHERE ID1 = 1 AND ID2 IN (1,2)
      UNION
      SELECT * FROM tbl1 WHERE ID1 = 3 AND ID2 IN (5,2) 
      

      SELECT * FROM tbl1 WHERE (ID1 = 1 AND ID2 IN (1,2)) OR (ID1 = 3 AND ID2 IN (5,2)) 
      

      【讨论】:

        【解决方案5】:

        你也可以试试

        SELECT * FROM tbl1 JOIN ( SELECT 1 AS ID1, 1 AS ID2 UNION ALL SELECT 1 AS ID1, 2 AS ID2 UNION ALL SELECT 2 AS ID1, 4 AS ID2 UNION ALL SELECT 2 AS ID1, 1 AS ID2 UNION ALL SELECT 3 AS ID1, 1 AS ID2 UNION ALL SELECT 3 AS ID1, 2 AS ID2 UNION ALL SELECT 3 AS ID1, 5 AS ID2 ) as keylist ON tbl1.ID1 = keylist.ID1 AND tbl1.ID2 = keylist.ID2

        【讨论】:

        • 如果有人想使用这个可怕的构造,请务必将其设为UNION ALL。此外,除了第一个 union-SELECT 之外,不需要提供列别名。
        • @ErwinBrandstetter 感谢 UNION ALL 的提醒,我忘记了在这种情况下您会获得微不足道的性能优势,因为结果集太小了。我保留字段名称的原因是为了便于阅读。这是因为我认为代码的目标应该在实际代码中明确。程序员应该只在需要改进时才关注性能..
        猜你喜欢
        • 2018-09-14
        • 2020-01-22
        • 1970-01-01
        • 1970-01-01
        • 2019-12-15
        • 2015-04-10
        • 2021-03-22
        • 2018-07-11
        • 1970-01-01
        相关资源
        最近更新 更多