2012-08-22 61 views
1

我有以下表格:如何创建此查询?

actions(id, name) 
orders(refno, po) 
order_actions(order, action) 

我想获得所有尚未执行的特定动作的命令。订单可能包含或不包含任何行为。

假设我想获得所有尚未应用的动作13订单,到目前为止,我有这样的事情:

SELECT o.po, oa.action, 
    FROM orders AS `o` 
    LEFT JOIN order_actions AS `oa` ON o.refno = oa.order 
WHERE oa.action <> 13 

这与有没有订单的动作效果很好,但如果一个订单的行为与13不同,我得到误报,我是否错过了另一个涉及actions表的加入,或者是GROUP BY或po的额外WHERE子句?

任何帮助表示赞赏。

+0

您正在使用哪些DBMS? –

+0

MySQL,谢谢你的回复。 – Triztian

回答

1

您可以通过和having子句也是解决这个问题的一组:如果你想保持轨迹上,这样订单的所有行动

SELECT o.refno, o.po 
FROM orders AS `o` LEFT JOIN 
    order_actions `oa` 
    ON o.refno = oa.order 
group by o.refno, o.po 
having max(case when oa.action = 13 then 1 else 0 end) = 0 

,您可以使用GROUP_CONCAT:

SELECT o.refno, o.po, 
     group_concat(cast(ao.action) separator ', ') as AllOtherActions 
FROM orders AS `o` LEFT JOIN 
    order_actions `oa` 
    ON o.refno = oa.order 
group by o.refno, o.po 
having max(case when oa.action = 13 then 1 else 0 end) = 0 
+0

似乎很复杂。虽然有趣的方法。 –

+0

@JohnBingham。 。 。这取决于你怎么看了。对我而言,使用having子句来过滤集合中的成员看起来并不复杂。事实上,它似乎比相关的子查询更简单。 –

+0

完全同意,你的查询是我的想法,但不知道如何在SQL中表达它。 – Triztian

3
SELECT o.po, oa.action 
FROM orders AS `o` 
    LEFT JOIN order_actions AS `oa` ON o.refno = oa.order 
WHERE NOT EXISTS (
    SELECT 1 
    FROM order_actions tmp 
    WHERE oa.order = tmp.order 
    AND tmp.action = '13' 
) 

DEMO(sqlfiddle)。

+0

为什么'1'值,你介意解释一下我试过查询,它需要很长时间,它还没有完成执行。我有大约2.3万个订单和5万个订单操作。 – Triztian

+0

你有'行动'专栏的索引吗? 'order'是'order_actions'中的主键吗? '1'只是为了使'SELECT'不是空的,它可以是''X''或任何列'tmp.order',因为我们对这个子选择的结果不感兴趣,只有当它返回或不包含'NOT EXISTS'的行。 –

+0

我创建了这个索引,事实上'orders(id)'是一个主键,它仍然是永久的。不管怎么说,多谢拉。 – Triztian

0

替代方案是这样的:

select o.po 
from orders as 'o' 
    left join (
     select order from order_actions where [action] = @Action 
     ) AS `oa` on o.refno = oa.order 
where oa.order is null 

这不会返回您选择的订单的操作号码,但你已经表明你只是在寻找没有采取行动的订单,我在这里参考的是@Action