选择一个日期但不存在另一个日期的记录?

时间:2013-02-23 14:13:04

标签: mysql sql join

如果我有一个表t1,它会查看记录在项目,大小和日期的组合上是唯一的;

item    size    date
1234    S   2013-02-11
1234    M   2013-02-11
1234    L   2013-02-11
9999    S   2013-02-11
9999    M   2013-02-11
9999    L   2013-02-11
1234    S   2013-02-13
1234    M   2013-02-13
1234    L   2013-02-13
9999    S   2013-02-13
9999    M   2013-02-13

与2013-02-11相比,如何检索2013-02-13中缺少的项目和大小?

我正在寻找的回报是,

item    size
9999    L

我试过了;

SELECT ta.item, 
         ta.size
FROM t1 ta 
    LEFT JOIN t1 tb 
        ON ta.item = tb.item
            AND ta.size = tb.size
WHERE ta.date = '2013-02-11'
   AND tb.date = '2013-02-13'
   AND tb.size IS NULL

SELECT item, size 
FROM t1
WHERE t1.date = '2013-02-11'
   AND NOT EXISTS (
                    SELECT item, size 
                    FROM t1
                    WHERE t1.date = '2013-02-13'
                  )

都返回空集。

我设法让它工作的唯一方法是使用临时表;

CREATE temporary table temp1
SELECT * FROM t1 WHERE date = '2013-02-11';

CREATE temporary table temp2
SELECT * FROM t1 WHERE date = '2013-02-13';

SELECT temp1.item, temp1.size FROM temp1
   LEFT JOIN temp2 
        ON temp1.item = temp2.item AND temp1.size = temp2.size
WHERE temp2.size IS NULL

临时表是不可能的。如何在不使用临时表的情况下实现这一目标?

非常感谢,

(请温柔,我刚开始!)

4 个答案:

答案 0 :(得分:4)

SELECT  a.*
FROM
        (
            SELECT  item, size
            FROM    tableName
            WHERE   date = '2013-02-11'
        ) a
        LEFT JOIN
        (
            SELECT  item, size
            FROM    tableName
            WHERE   date = '2013-02-13'
        ) b ON  a.item = b.item AND
                a.size = b.size
WHERE b.size IS NULL

答案 1 :(得分:1)

使用聚合查询:

select item, size
from t1
group by item, size
having sum(case when date = '2013-02-11' then 1 else 0 end) = 1 and
       sum(case when date = '2013-02-13' then 1 else 0 end) = 0

这是“群组内”群组查询的示例。通过改变having子句,您可以在要满足的条件下具有很大的灵活性。例如:

having sum(case when date = '2013-02-11' then 1 else 0 end) = 0 or
       sum(case when date = '2013-02-13' then 1 else 0 end) = 0

将返回数据中存在的组合,但在任何一天都会丢失。

答案 2 :(得分:0)

您也可以尝试这个简单的查询

SELECT item, size FROM dbo.Table_1 WHERE date = '2013-02-11'
EXCEPT
SELECT item, size FROM dbo.Table_1 WHERE date = '2013-02-13'

答案 3 :(得分:0)

其他人为您提供了有效的解决方案,这篇文章仅解决您失败的尝试,解释遗漏的内容以及如何修复。

此查询

SELECT ta.item, 
         ta.size
FROM t1 ta 
    LEFT JOIN t1 tb 
        ON ta.item = tb.item
            AND ta.size = tb.size
WHERE ta.date = '2013-02-11'
   AND tb.date = '2013-02-13'
   AND tb.size IS NULL

失败,因为WHERE子句中存在矛盾。查询正在尝试查找tb.size为NULL的行,这意味着tb实例与ta实例不匹配, tb.date是一个特殊值。现在,如果tb中没有匹配项,则其所有列都将返回为NULL,其中包含tb.date,这意味着它不能等于某个值并且同时为空。

显然,你的意图不同了。您希望将表的一个子集左连接到另一个子集(同一个表中的子集)。在这种情况下,定义要加入的子集的条件应该放入ON子句中。也就是说,您没有加入两个实例的itemsize列匹配的唯一条件,但是在匹配的那些列的组合条件下,其他实例的匹配date是一个特定的价值。所以,这就是你应该拥有的东西:

SELECT ta.item, 
         ta.size
FROM t1 ta 
    LEFT JOIN t1 tb 
        ON ta.item = tb.item
            AND ta.size = tb.size
            AND tb.date = '2013-02-13'
WHERE ta.date = '2013-02-11'
   AND tb.date = '2013-02-13'
   AND tb.size IS NULL

另一个查询

SELECT item, size 
FROM t1
WHERE t1.date = '2013-02-11'
   AND NOT EXISTS (
                    SELECT item, size 
                    FROM t1
                    WHERE t1.date = '2013-02-13'
                  )

似乎是EXISTSIN混淆的结果。

首先,EXISTS如何运作。当子查询返回非空行集时,它返回true。哪个列无关紧要,只有行的存在才算重要。如果未返回,则结果为false。这样,您的查询如下所示:

  

返回date'2013-02-11'并且<{1}}没有任何行的每一行。

虽然您可能想通过该查询说出类似的内容:

  

返回date = '2013-02-11'date并且相同行没有相同 '2013-02-11'和{{1}的每一行和} item的{​​{1}}。

也就是说,您需要将EXISTS子查询与主查询相关联,这意味着将当前行的sizedate包含在EXISTS测试中。所以,这就是修复可能的样子:

'2013-02-11'

另一方面,您可以重写相同的查询以使用size而不是item。这里:

SELECT item, size 
FROM t1 ta
WHERE ta.date = '2013-02-11'
   AND NOT EXISTS (
                    SELECT item, size 
                    FROM t1 tb
                    WHERE tb.date = '2013-02-13'
                      AND ta.item = tb.item
                      AND ta.size = tb.size
                  )

基本上说:

  

返回NOT IN NOT EXISTSSELECT item, size FROM t1 WHERE date = '2013-02-11' AND (item, size) NOT IN ( SELECT item, size FROM t1 WHERE date = '2013-02-13' ) 对不在(item, size) date = '2013-02-11'对中的每一行。

(item, size) / date = '2013-02-11'查询通常看起来比其IN / NOT IN对象更清晰。这两个是否会导致相同的查询计划是另一回事,您应该在决定使用哪种方法之前进行测试(当然,这也适用于EXISTS方法)。