【问题标题】:WHERE using a temporary tableWHERE 使用临时表
【发布时间】:2013-09-24 13:34:12
【问题描述】:

我有三个表:客户、订单和退款。部分客户(并非全部)下单,部分订单(并非全部)获得了退款。

当我像这样加入三个表时(细节不是那么重要):

SELECT ...
FROM customers LEFT JOIN orders
ON customers.customer_id=orders.customer_id    
LEFT JOIN refunds
ON orders.order_id=refunds.order_id;
//WHERE order_id IS NOT NULL;// uncomment to filter out customers that have no orders

我得到一个大表,其中列出了所有客户(即使是那些没有下任何订单并且他们在 'order_id' 列中有 NULL 的客户),以及他们的所有订单和订单的退款(即使不是全部订单有退款):

NAME     ORDER_ID    ORDER AMOUNT   REFUND
------------------------------------------------------------
Natalie   2         12.50           NULL
Natalie   3         18.00           18.00
Brenda    4         20.00           NULL
Adam      NULL      NULL            NULL    

由于我只想查看已下订单的客户,即在本例中我想从表中过滤 Adam,因此我取消了上面 SQL 查询中“WHERE”行的注释。 这产生了预期的结果。 我的问题是: 在哪个表上执行 WHERE - 在原始“订单”表(没有为 NULL 的 order_id)或作为 JOIN 的结果的表上? 显然是后者,但只是想确定一下,因为从SQL语法上看不是很明显,而且很重要。

谢谢

【问题讨论】:

  • 为什么不遍历执行计划,看看它在哪里呢?虽然我同意,但它往往发生在茶几。

标签: sql join where


【解决方案1】:

在这种情况下,您使 SQL 工作变得比它必须的更努力。它对结果进行操作(可能是 MERGE 事件,或类似的事情)。

SQL 有可能意识到您在做什么并优化计划并为您更改为INNER JOIN。但我不能确定(SQL 也不能确定——它可以随着时间的推移改变它的优化方式)。

如果您只想要订单所在的位置,请改用INNER JOIN。 SQL 在这方面会更有效率。

SELECT ...
FROM customers
INNER JOIN orders
ON customers.customer_id=orders.customer_id    
LEFT JOIN refunds
ON orders.order_id=refunds.order_id;

【讨论】:

  • 你是绝对正确的,我真的试过这个。但我也出于教育目的运行此代码(实际上来自一本书)。
  • 即便如此,我想我还是用“视情况而定”回答了这个问题。 SQL 很聪明。它通常可以基于优化解决问题。您只有在运行和分析该计划时才能确定。即便如此,也只会为您提供当前优化的通行证。如果 SQL 更改其统计信息并认为以另一种方式执行会产生更好的结果,它将稍后重新优化查询。你最好尽可能明确地“保证”一个计划。
  • 我在另一个线程 (stackoverflow.com/questions/13132447/…) 上找到了答案。
【解决方案2】:

您可以将LEFT JOIN更改为INNER JOIN,以消除没有任何订单的客户

SELECT ...
FROM customers INNER JOIN orders
ON customers.customer_id=orders.customer_id    
LEFT JOIN refunds
ON orders.order_id=refunds.order_id;

【讨论】:

    【解决方案3】:

    这是因为您使用的是LEFT JOIN,它将返回左侧表格中的所有行,在您的情况下,这是Customer 表格,并返回NULL,右侧表格中没有出现相应的值.

    只需使用内部连接重写它,因此只会返回找到匹配数据的行。

    SELECT ...
    FROM customers 
    INNER JOIN orders
        ON customers.customer_id=orders.customer_id    
    INNER JOIN refunds
        ON orders.order_id=refunds.order_id;
    

    【讨论】:

      猜你喜欢
      • 2010-11-14
      • 2011-08-24
      • 2011-05-21
      • 2018-04-12
      • 1970-01-01
      • 1970-01-01
      • 2010-12-25
      • 2010-10-12
      • 1970-01-01
      相关资源
      最近更新 更多