2

数据库 - Microsoft Adventureworks

表 - Sales.SalesOrderHeader

问题 -哪些客户(即 customerID)在 2003 年 3 月或 2003 年 4 月订购了一些东西,但不是两者都订购了。

概念 -

获取蓝色部分,即A独有的元素/行和B 独有的元素/行。图片来源 - CodingHorror.com 的 Jeff Atwood

我的查询 -

select Soh.CustomerID, Soh.OrderDate 
from Sales.SalesOrderHeader as Soh
where Soh.OrderDate >= '2003-03-01' AND Soh.OrderDate < '2003-04-01' -- march only

UNION

select Soh.CustomerID, Soh.OrderDate 
from Sales.SalesOrderHeader as Soh
where Soh.OrderDate >= '2003-04-01' AND Soh.OrderDate < '2003-05-01' -- april only    
order by Soh.OrderDate asc;

我的问题-

我是否正确回答了问题?解决这个问题的任何其他方法,最好是更少的代码?

编辑 -哎呀。这只会在2个月内下订单而不回答问题。所以,我错了。试图修复它。

谢谢。

4

4 回答 4

3
SELECT  Cust.CustomerID
FROM    Sales.Customer AS Cust
        INNER JOIN Sales.SalesOrderHeader AS Soh
            ON Cust.CustomerID = Soh.CustomerID
WHERE   Soh.OrderDate >= '2003-03-01' AND Soh.OrderDate < '2003-05-01'
GROUP   BY Cust.CustomerID
HAVING  COUNT(DISTINCT CASE WHEN MONTH(Soh.OrderDate) = 3 AND
                                YEAR(Soh.OrderDate) = 2003 THEN 1 ELSE 2 END) = 1

嗯,,,,SELECT并且是FROM非常不言自明的。这里棘手的部分是子句。所以让我简化一下,您看到的语句给出了一个将记录分类为组的值。代替and ,我将使用and使其更易于理解。WHEREGROUP BYHAVINGCASE12MarchApril

SELECT  CustomerID,
        CASE WHEN MONTH(OrderDate) = 3 AND YEAR(OrderDate) = 2003 
              THEN 'March' 
              ELSE 'April'
        END AS MonthBought
FROM    TableName
WHERE   OrderDate >= '2003-03-01' AND OrderDate < '2003-05-01'

正如您在演示中看到的那样,当订单日期在March, 2013任何日期的月份时,对应的值为 ,否则MonthBought因为March我们April确定所有记录都在March and April 2013WHERE子句之间。

该子句过滤所有在to onlyHAVING中具有唯一值数量的记录,这意味着客户仅在某个月份购买。MonthBought1

于 2013-09-18T22:04:49.843 回答
1
CREATE TABLE table_a ( id INTEGER NOT NULL PRIMARY KEY
   , OrderDate DATE NOT NULL DEFAULT '2003-03-15');
CREATE TABLE table_b ( id INTEGER NOT NULL PRIMARY KEY
   , OrderDate DATE NOT NULL DEFAULT '2003-04-15');

INSERT INTO table_a(id) VALUES (0),(2),(4),(6),(8),(10),(12),(14),(16),(18),(20);
INSERT INTO table_b(id) VALUES (0),(3),(6),(9),(12),(15),(18),(21);


SELECT COALESCE (a.id, b.id) AS id
FROM (
        SELECT DISTINCT id
        FROM table_a
        WHERE OrderDate >= '2003-03-01' AND OrderDate < '2003-04-01'
        ) a
FULL OUTER JOIN (
        SELECT DISTINCT id
        FROM table_b
        WHERE OrderDate >= '2003-04-01' AND OrderDate < '2003-05-01'
        )  b ON b.id = a.id
WHERE a.id IS NULL OR b.id IS NULL
        ;

注意:我必须发明自己的数据,因为 OP 没有提供任何数据,而且我懒得输入。

更新:原始 UNION 查询(​​此处使用 table_a/table_b 构造,对于原始数据模型,使用 table_a = table_b = Sales.SalesOrderHeader

SELECT a.id, a.OrderDate
FROM table_a as a
WHERE a.OrderDate >= '2003-03-01' AND a.OrderDate < '2003-04-01' -- march only
AND NOT EXISTS (
        SELECT * FROM table_b nx
        WHERE nx.id = a.id
        AND nx.OrderDate >= '2003-04-01' AND nx.OrderDate < '2003-05-01' -- april only
        )
UNION ALL
SELECT b.id, b.OrderDate
FROM table_b as b
WHERE b.OrderDate >= '2003-04-01' AND b.OrderDate < '2003-05-01' -- april only    
AND NOT EXISTS (
        SELECT * FROM table_a nx
        WHERE nx.id = b.id
        AND nx.OrderDate >= '2003-03-01' AND nx.OrderDate < '2003-04-01' -- march only
        )
ORDER BY OrderDate ASC;

笔记:

  • UNION应该是 a ,UNION ALL因为重复是不可能的,并且不必被删除
  • 这些NOT EXISTS ()子句是必要的:您想要 3 月份的记录,而 4 月份不存在,反之亦然。
  • 需要UNION通常表明数据模型次优(在这种情况下不是)
  • FULL OUTER JOIN可以认为是关系划分的一种特殊形式
于 2013-09-18T22:15:01.237 回答
0

不,您没有正确回答问题。“联合”为您提供了第一个查询 (A) 的所有结果以及第二个查询的所有结果,其中尚未返回结果。

不错的图形!

于 2013-09-18T21:56:23.540 回答
0

好吧,我想我终于明白了。答案 - 746 行查询 -

-- Customers who had an order on Mar or Apr, but not both
select Ord.CustomerID
from Sales.SalesOrderHeader as Ord
where (Ord.OrderDate >= '2003-03-01' AND Ord.OrderDate < '2003-04-01') -- all March
or (Ord.OrderDate >= '2003-04-01' AND Ord.OrderDate < '2003-05-01') -- all April

except 

select MarchAndApril.CustomerID
from
(
select Ord.CustomerID
from Sales.SalesOrderHeader as Ord
where (Ord.OrderDate >= '2003-03-01' AND Ord.OrderDate < '2003-04-01') -- March

intersect

select Ord.CustomerID
from Sales.SalesOrderHeader as Ord
where (Ord.OrderDate >= '2003-04-01' AND Ord.OrderDate < '2003-05-01') -- April
) as MarchAndApril

order by Ord.CustomerID

这是一个不同的示例数据集,可以让事情变得简单。

表 - 订单

列 - CustomerID(PK, int, Not null), OrderDate(date, not null) 仅在 1 月、2 月、7 月下订单。

1   2012-01-01
1   2012-01-02
1   2012-02-01
2   2012-01-01
2   2012-02-01
3   2012-01-01
4   2012-02-01
5   2012-07-01

新问题 - 获取 1 月或 2 月有订单的客户,但不能同时获得。

策略 - 在 1 月和 2 月获得客户。然后,从该集合中删除在 1 月和 2 月都有订单的客户。

我们预计结果为 3,4。确实如此。

-- Customers who had an order on Jan or Feb, but not both
select Ord.CustomerID
from Orders as Ord
where (Ord.OrderDate >= '2012-01-01' AND Ord.OrderDate < '2012-02-01') -- all January
or (Ord.OrderDate >= '2012-02-01' AND Ord.OrderDate < '2012-03-01') -- all February

--We can replace this where + or by a UNION ??? I got the same results, ie 3,4

except 

select JanuaryAndFebruary.CustomerID
from
(
select Ord.CustomerID
from Orders as Ord
where (Ord.OrderDate >= '2012-01-01' AND Ord.OrderDate < '2012-02-01') -- January

intersect

select Ord.CustomerID
from Orders as Ord
where (Ord.OrderDate >= '2012-02-01' AND Ord.OrderDate < '2012-03-01') -- February
) as JanuaryAndFebruary

order by Ord.CustomerID
于 2013-09-19T00:49:58.857 回答