【问题标题】:Finding unmatched records with SQL使用 SQL 查找不匹配的记录
【发布时间】:2009-02-03 19:22:33
【问题描述】:

我正在尝试编写查询以查找在另一个表中没有匹配记录的记录。

例如,我有两个表,其结构如下所示:

表格1 状态 |产品 |经销商 |其他领域 加利福尼亚州 | P1 |一个 | xxxx 或 | P1 |一个 | xxxx 或 | P1 |乙| xxxx 或 | P1 | X | xxxx 西澳 | P1 | X | xxxx 弗吉尼亚州 | P2 |一个 | xxxx 表2 状态 |产品 |版本 |其他领域 加利福尼亚州 | P1 | 1.0 | xxxx 或 | P1 | 1.5 | xxxx 西澳 | P1 | 1.0 | xxxx 弗吉尼亚州 | P2 | 1.2 | xxxx

(State/Product/Distributor 共同构成 Table1 的 key。State/Product 是 Table2 的 key)

我想查找所有未使用分发服务器 X 的 State/Product/Version 组合。(因此本示例中的结果是 CA-P1-1.0 和 VA-P2-1.2。)

对查询有什么建议吗?

【问题讨论】:

  • 从你的第二句到最后一句,table2 是否应该参与这个查询? (除了可能获得产品的版本)。
  • 我想你回答了你自己的问题。 Table2 是获取版本所必需的。

标签: sql select


【解决方案1】:
SELECT
    *
FROM
    Table2 T2
WHERE
    NOT EXISTS (SELECT *
        FROM
           Table1 T1
        WHERE
           T1.State = T2.State AND
           T1.Product = T2.Product AND
           T1.Distributor = 'X')

这应该符合 ANSI。

【讨论】:

  • 这适用于大多数 SQL 系统; EXCEPT 不会在任何地方都起作用(尽管它在起作用的地方更优雅)。
  • 在子查询中使用“SELECT 1 FROM”(而不是“SELECT * FROM”)可以防止不必要的表扫描。虽然我希望 DBMS 足够聪明,可以在看到“EXISTS”时自行解决。
  • 我和我的 SQL Server MVP 同事一直都有这个 :-) * 在编译时扩展,bt 微不足道,但他说运行时没有。有一次他给我看了一篇文章。不久前我看到了 Itzak Ben-Gan,他说 * 更快。选择权在你...
  • 当使用 EXISTS 时,SELECT * 和 SELECT 1 应该没有区别。
  • @Dems 这并不完全正确。在 Oracle 中,EXISTS 子句中的SELECT * 进行了特别优化。后来,在互联网部落开始推荐SELECT 1 之后,他们不得不返回并更改他们的代码以适应它。另外,根据至少一年前的一篇博客,SELECT 1 在执行计划构建期间在 Sql Server 中效率更高。这是一个折腾...提出全球建议显然充满危险。
【解决方案2】:

在 T-SQL 中:

SELECT DISTINCT Table2.State, Table2.Product, Table2.Version
FROM Table2 
  LEFT JOIN Table1 ON Table1.State = Table2.State AND Table1.Product = Table2.Product AND Table1.Distributor = 'X'
WHERE Table1.Distributor IS NULL

不需要子查询。

编辑:正如 cmets 所示,DISTINCT 不是必需的。谢谢!

【讨论】:

  • 我不会使用 distinct,否则这就是你想要的。
  • distinct 可能会使查询效率降低,但永远不会提高效率。这取决于相对表行数。 distcnt 还强制进行子查询不需要的聚合。
  • 此查询的性能和行为还很大程度上取决于Distributor 是否被连接中使用的索引覆盖(如果没有,则可能需要查找或索引操作可能必须转换为聚集索引操作)以及Distributor 是否可以为 NULL(在这种情况下,除了不匹配的行之外,它可能会返回缺少值的匹配行)。
  • 如果分发服务器可以为空怎么办?
【解决方案3】:

select * from table1 where state not in (select state from table1 wheredistributor = 'X')

可能不是最聪明的,但应该可以。

【讨论】:

  • IN 不如 EXISTS,不处理 state/product 上的复合键
  • 如果state 可以为空,NOT IN 的行为也不会像您期望的那样。
【解决方案4】:
SELECT DISTINCT t2.State, t2.Product, t2.Version
FROM table2 t2
JOIN table1 t1 ON t1.State = t2.State AND t1.Product = t2.Product
                AND t1.Distributor <> 'X'

【讨论】:

    【解决方案5】:

    在甲骨文中:

    SELECT t2.State, t2.Product, t2.Version
    FROM Table2 t2, Table t1
    WHERE t1.State(+) = t2.State
      AND t1.Product(+) = t2.Product
      AND t1.Distributor(+) = :distributor
      AND t1.State IS NULL
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多