MySQL加入“WHEN” - 这样的事情可能吗?

时间:2014-10-13 12:13:42

标签: mysql sql join

背景:

  • 我正在运行一个查询,该查询获取客户在上个月订购的总小部件 sprockets gizmos
  • 我还有一个 Total Orders 列,它运行一个子查询,计算当月的每个订单
  • 我在子查询中执行 Total Orders 的原因,而不仅仅是添加三列,是因为我还有两个 Total Orders 列用于前两个个月
  • 我有一个存储财务记录的订单表,以及小部件 sprockets 的实际产品详细信息的单独表格小玩意

问题:

  • 有时,小部件可能会被半删除' (不要问!) - 它有订单记录,但没有相应的小部件记录
  • 我不想在 Total Widgets 列中计算这一点 - 这很容易,因为我只是做JOIN
  • 但是,我也不想在总订单列中计算...

我的当前查询对于 Total Widgets

是这样的
SELECT 
    COUNT(orders.id)
FROM orders
JOIN widgets ON widgets.id = orders.item_id
WHERE orders.product_id = 1 -- Product ID 1 is a Widget
AND orders.date BETWEEN "2014-09-01 00:00:00" AND "2014-09-30 23:59:59"

所以这将使所有人都准确无误。小部件,具有完整的widget表记录。

以下是 Total Orders 的当前查询:

SELECT 
    COUNT(orders.id) AS count
FROM orders
JOIN widgets ON widgets.id = orders.item_id AND orders.product_id = 1
WHERE orders.date BETWEEN "2014-09-01 00:00:00" AND "2014-09-30 23:59:59"

所以我的想法是,当订单的JOIN为1时,上述查询应该只有product_id。但是,在每种情况下都是JOIN。这意味着如果我们订购了10个小部件(其中2个已被半删除),5个链轮和5个小玩意儿,而不是显示18个订单,则仅显示8.更改为LEFT JOIN显示20 ,这仍然是错的,它应该是18。

希望上述内容有意义 - 提前感谢。

1 个答案:

答案 0 :(得分:0)

好吧......直接联接不起作用,因为你过滤了orders.product_id = 1因此它不会计算链轮或小玩意。只是小部件。如果你有2个半删除,但有10个记录...... 8是正确的答案。 left outer join允许它加入product_id <> 1的行,所以来自orders的所有行(包含小部件,链轮,小发明的订单记录 - 一半删除或不删除)。但这也允许那些2个删除的行。

为什么不直接加入?如果你想要答案18,只需加入订单和产品并计算。不要仅过滤小部件。如果你不想删除一半,请不要做左外。

create table product (
   product_id int,
   product_name varchar(20)
);

insert into product values (1,'widget'); 
insert into product values (2,'sprocket'); 
insert into product values (3,'gizmo'); 

create table `order` (
   order_id  int,
   widget_id int  
); 

insert into `order` values (1,1); 
insert into `order` values (1,2); 
insert into `order` values (1,3); 
insert into `order` values (1,4);  -- half deleted
insert into `order` values (2,1); 
insert into `order` values (2,2);  
insert into `order` values (3,3); 
insert into `order` values (3,4);  -- half deleted  
insert into `order` values (4,4);  -- half deleted 



select   o.order_id, count(*)
from     `order` as o 
         join product as p  
            on o.widget_id=p.product_id   
group    by o.order_id     


+----------+----------+
| order_id | count(*) |
+----------+----------+
|        1 |        3 |
|        2 |        2 |
|        3 |        1 |
+----------+----------+
3 rows in set (0.00 sec)

mysql> select   o.order_id,
    ->          p.product_name,
    ->          (case when p.product_id is null
    ->                then 'half_deleted' else '' end) as half_deleted
    -> from     `order` as o
    ->          left outer join product as p
    ->             on o.widget_id=p.product_id
    -> order    by order_id   ;
+----------+--------------+--------------+
| order_id | product_name | half_deleted |
+----------+--------------+--------------+
|        1 | gizmo        |              |
|        1 | NULL         | half_deleted |
|        1 | widget       |              |
|        1 | sprocket     |              |
|        2 | widget       |              |
|        2 | sprocket     |              |
|        3 | gizmo        |              |
|        3 | NULL         | half_deleted |
|        4 | NULL         | half_deleted |
+----------+--------------+--------------+