【问题标题】:SQL Sub-Query vs Join ConfusionSQL 子查询与连接混淆
【发布时间】:2010-09-30 22:27:42
【问题描述】:

我有一个在 Access 中的数据库(你可以得到它link text)。如果我跑

SELECT DISTINCT Spl.Spl_No, Spl.Spl_Name
FROM Spl INNER JOIN Del 
   ON Spl.Spl_No = Del.Spl_No
WHERE Del.Item_Name <> 'Compass'

它提供了从未交付过指南针的供应商的名称。但是,您可以使用子查询来执行此操作。到目前为止,我自己和其他一些人都无法做到这一点。

我确实做到了以下几点,直到我们添加更多供应商然后它停止工作

SELECT SPL.SPL_Name
FROM SPL
LEFT JOIN DEL ON Del.SPL_No = SPL.SPL_No
WHERE (DEL.Item_Name<>"Compass") OR (DEL.Item_Name IS NULL)
GROUP BY SPL.SPL_Name
HAVING COUNT(DEL.SPL_No) = 0

所以问题是:这可能与子查询有关吗?

【问题讨论】:

  • 既然已经将子查询作为连接,为什么还要使用子查询呢?顺便说一句,您给出的第二个示例没有使用子查询!
  • 第一个示例不起作用 - 供应商可能已经交付了指南针,但只要他们还交付了其他东西,他们仍然会出现。
  • 另外:供应商可能会出现多次:对于每种交付的非指南针类型的物品一次。
  • 另外,第一个查询不会列出那些从未交付过任何东西的供应商 - 它只会列出那些交付过除指南针以外的东西的供应商(省略那些只交付过指南针的供应商,以及那些从未交付过任何东西)。

标签: sql ms-access join


【解决方案1】:

我想我会去:

SELECT SELECT Spl_No, Spl_Name
FROM Spl
WHERE Spl_No NOT IN 
  (SELECT Spl_No FROM Del
   WHERE Item_Name = 'Compass')

【讨论】:

    【解决方案2】:

    这与你用英语所说的方式非常接近

    “给我没有交付 Compass 的供应商。”

    Select [Stuff]
    From Spl S
    Where Not Exists
       (Select * From Del
        Where Spl_no = S.Spl_no 
           And Item_name  = 'Compass')
    

    编辑: 如果没有 Exists,您可以使用 Count(*) = 0

    Select [Stuff]
    From Spl S
    Where 
       (Select Count(*) From Del
        Where Spl_no = S.Spl_no 
           And Item_name  = 'Compass') = 0
    

    【讨论】:

      【解决方案3】:

      如果 Access 存在.....

      选择 SPL.SPL_Name 来自 SPL 不存在的地方(从 DEL 中选择 1,其中 Del.SPL_No = SPL.SPL_No AND (DEL.Item_Name='指南针') )

      【讨论】:

      • Jet SQL 支持 EXISTS,但它并未在所有情况下都针对使用索引进行了很好的优化。在我看来,IN 似乎更充分地利用了索引,尽管 NOT IN 没有。去图吧。
      【解决方案4】:

      你的意思是这样的吗?

      SELECT SPL.SPL_Name
      FROM SPL
      WHERE NOT SPL.SPL_no IN 
       (SELECT SPL_no FROM DEL WHERE DEL.Item_Name = "Compass") 
      

      【讨论】:

        【解决方案5】:
        SELECT Spl_No
             , Spl_Name
          FROM Spl
         WHERE NOT EXISTS( SELECT *
                             FROM Del
                            WHERE Del.Spl_no = Spl.Spl_no
                              AND Item_name  = 'Compass' )
        

        【讨论】:

          【解决方案6】:

          这是你要找的吗?

          SELECT
             SPL.SPL_name
          FROM
             SPL
          WHERE
             SPL.SPL_No NOT IN
             (
                SELECT SPL_No FROM DEL WHERE DEL.Item_Name <> "Compass"
             )
          

          【讨论】:

          • 你不希望 在子查询中
          【解决方案7】:

          从未交付过指南针的供应商:

          SELECT Spl.Spl_No, Spl.Spl_Name
          FROM Spl
          LEFT JOIN Del ON Del.Spl_No = Spl.Spl_No AND Del.Item_Name = 'Compass'
          WHERE Del.Item_Name IS NULL
          

          并使用子查询:

          SELECT Spl_No, Spl_Name
          FROM Spl
          WHERE Spl_No IN 
            (
              SELECT Spl_No
              FROM Del
              GROUP BY Spl_No, Item_Name
              WHERE Item_Name = 'Compass'
              HAVING COUNT(*) = 0
            )
          

          【讨论】:

          • 子查询太复杂。优化器可能决定将其优化为更简单的 IN 或 EXISTS,但可能不会。无论如何,它在语法上也很复杂,没有真正的原因。为什么要让一个人更难解析?
          • 这是一个功能,而不是一个错误;)我想引导他使用 JOIN 版本。
          • 加入版本很奇怪——那些 item_name 为 compass 而 item_name 为 null 的供应商;是的,没错,但很奇怪。
          • 不适用于 Access - 似乎 WHERE 和 GROUP 子句是错误的方法。此外,如果您将它们扫地出门,您将一无所获。
          • 不过,加入版本是 Access 的正确方法。当您使用 IN、NOT IN、EXISTS 等时,Access 的性能会变得非常糟糕。您需要执行 LEFT JOIN 并测试 NULL,尽管它可能很丑陋。
          猜你喜欢
          • 2015-04-16
          • 1970-01-01
          • 2014-04-18
          • 1970-01-01
          • 1970-01-01
          • 2019-05-19
          • 1970-01-01
          • 2013-04-26
          • 2011-04-20
          相关资源
          最近更新 更多