如何确保使用过滤器进行外连接仍会返回所有需要的行?

时间:2011-11-07 23:00:08

标签: sql left-join outer-join

想象一下,我在DB中有两个表:

products:    
product_id  name
----------------
1           Hat
2           Gloves
3           Shoes

sales:
product_id  store_id  sales
----------------------------
1           1         20
2           2         10

现在我想查询列出所有产品及其销售情况,因为store_id = 1.我的第一个问题是使用左连接,过滤到我想要的store_id,或者null store_id,如果产品没有在store_id = 1获得任何销售,因为我想要列出所有产品:

SELECT name, coalesce(sales, 0)
FROM products p
LEFT JOIN sales s ON p.product_id = s.product_id
WHERE store_id = 1 or store_id is null;

当然,这不会按预期工作,而是我得到:

name   sales
---------------
Hat    20
Shoes  0

没有手套!这是因为Gloves确实得到了销售,而不是在store_id = 1,所以WHERE子句已将它们过滤掉了。

如何才能获得特定商店的所有产品及其销售清单?

以下是创建测试表的一些查询:

create temp table test_products as 
select 1 as product_id, 'Hat' as name;
insert into test_products values (2, 'Gloves');
insert into test_products values (3, 'Shoes');
create temp table test_sales as
select 1 as product_id, 1 as store_id, 20 as sales;
insert into test_sales values (2, 2, 10);

更新:我应该注意到我知道这个解决方案:

SELECT name, case when store_id = 1 then sales else 0 end as sales
FROM test_products p
LEFT JOIN test_sales s ON p.product_id = s.product_id;

然而,它并不理想......实际上我需要为BI工具创建此查询,使得工具可以简单地向查询添加where子句并获得所需的结果。此工具不支持将所需的store_id插入此查询中的正确位置。所以我正在寻找其他选择,如果有的话。

2 个答案:

答案 0 :(得分:2)

将WHERE条件添加到LEFT JOIN子句以防止丢失行。

SELECT p.name, coalesce(s.sales, 0)
FROM   products p
LEFT   JOIN sales s ON p.product_id = s.product_id
                   AND s.store_id = 1;

编辑其他请求:

我假设您可以操纵SELECT项目?然后这应该做的工作:

SELECT p.name
      ,CASE WHEN s.store_id = 1 THEN coalesce(s.sales, 0) ELSE NULL END AS sales
FROM   products p
LEFT   JOIN sales s USING (product_id)

在这种情况下也简化了连接语法。

答案 1 :(得分:1)

我不在SQL附近,但请试一试:

SELECT name, coalesce(sales, 0)
FROM products p
LEFT JOIN sales s ON p.product_id = s.product_id AND store_id = 1

您不希望整个查询中的位置,只需要加入