2011-12-08 105 views
24

好吧,所以我有一个包含userID和taskID的临时表。它被称为CompletedTasks。我有第二个表包含用户ID和任务ID。它被称为PlannedTasks。mysql“哪里不在”使用两列

我需要获得已完成但未计划的所有任务ID的列表。所以,我需要以某种方式从完成的任务中清除所有行,其中两个都是PlannedTasks.userID != CompletedTasks.userID AND PlannedTasks.taskID != CompletedTasks.taskID

我希望这个问题有道理。请让我知道,如果不清楚,我会进一步解释。

感谢您的任何提示!

+0

我想你需要一个额外的列来指示状态,并不需要两个表。 – ajreal

+0

@ajreal这是一个很好的观点。也许我会考虑按照你的建议调整模式。欣赏提示! – PFranchise

+1

我比99%的时间更喜欢一张桌子和一张状态栏上的2张桌子。一张桌子上有11张桌子,还有10张状态栏。要优化搜索一个或多个状态列(在Mysql中)的查询并不容易。 –

回答

62

你可以使用这个(更紧凑语法):

SELECT * 
FROM CompletedTasks 
WHERE (userID, taskID) NOT IN 
     (SELECT userID, taskID 
     FROM PlannedTasks 
    ) ; 

NOT EXISTS版本(虽然比较复杂,应该是适当的索引更高效):

SELECT c.* 
FROM CompletedTasks AS c 
WHERE NOT EXISTS 
     (SELECT 1 
     FROM PlannedTasks AS p 
     WHERE p.userID = c.userID 
      AND p.taskID = c.taskID 
    ) ; 

,当然还有@jmacinnes在他的回答中提供的LEFT JOIN/IS NULL版本。

+0

太棒了!非常感谢你。我不知道你可以用这种方式在两个地方使用Where,但希望这是一个选择。再次感谢,祝你有美好的一天! – PFranchise

+0

继我的测试后,NOT EXISTS版本比NOT_IN版本 –

+0

@Ka更快。是的,带有元组的'NOT IN'没有像'NOT EXISTS'那样优化。你测试过哪个版本?我还没有测试过它们是否改进了新5.7版本的优化器。 –

5

这是你需要的吗?

select ct.* from 
completedTasks ct 
left outer join plannedTasks pt on ct.taskId = pt.TaskId and ct.userId = pt.userId 
where pt.taskId is null 

不过,我同意评论 - 鉴于我们从状态栏听起来比两个表一个更好的架构问题知道。

0

@ypercubeᵀᴹ感谢分享以下提到的查询

SELECT * FROM CompletedTasks WHERE (userID, taskID) NOT IN 
     (SELECT userID, taskID FROM PlannedTasks) ;' 

我的问题就迎刃而解了。

+0

这应该是一个评论,而不是答案:) – sniperd

+0

其实,我参考@ypercube共享查询做了一些更改。将来会保重。谢谢 –