我有一个客户表
+--------+---------+ | Id | Name | +--------+---------+ | 1 | A | | 2 | b | | 3 | c | | 4 | d | | 5 | 3 | | 6 | f | | 7 | g | +--------+---------+
和订单表
+-----+------+--------------------------+ | ID | C_Id | OrderDate | +-----+------+--------------------------+ | 1 | 1 | 2017-05-12 00:00:00.000 | | 2 | 2 | 2017-12-12 00:00:00.000 | | 3 | 3 | 2017-11-12 00:00:00.000 | | 4 | 4 | 2017-12-12 00:00:00.000 | | 5 | 1 | 2017-12-12 00:00:00.000 | | 6 | 2 | 2017-12-12 00:00:00.000 | | 7 | 3 | 2017-12-12 00:00:00.000 | | 8 | 4 | 2017-11-12 00:00:00.000 | | 9 | 2 | 2017-06-12 00:00:00.000 | | 10 | 3 | 2017-07-12 00:00:00.000 | +-----+------+--------------------------+
我需要上个月没有购买的顾客的结果。 这是客户3和4在上个月(11月)购买的订单表。结果不应包括客户3和4,即使他们在前几个月购买。
我有这个查询可以完美地返回结果。
SELECT C_ID , MONTH(OrderDate) from [Order]
WHERE MONTH(OrderDate) <> MONTH(GETDATE()) - 1
AND C_ID NOT IN (
SELECT C_ID FROM [Order]
WHERE MONTH(OrderDate) = MONTH(GETDATE()) - 1)
任何人都可以帮我写这个查询而不使用子查询
编辑: 为了更清晰,我需要将客户从结果中排除(获取当年的所有订单),如果他们在11月份有任何购买,我也需要结果仅一年。
答案 0 :(得分:0)
我认为您需要使用其他方式检查早期购买,因为MONTH(OrderDate) <> MONTH(GETDATE()) - 1
如果购买的时间不同,则会遇到问题。
你需要扩大你的条件。例如
(
(MONTH(OrderDate)<MONTH(DATEADD(MONTH,-1,GETDATE())) AND YEAR(OrderDate)=YEAR(DATEADD(MONTH,-1,GETDATE())))
OR YEAR(OrderDate)<YEAR(DATEADD(MONTH,-1,GETDATE()))
)
或者您可以使用EOMONTH
函数(来自SQL Server 2012)。我认为这种变体会更有用。
SELECT
C_ID,
MONTH(OrderDate)
FROM [Order]
WHERE EOMONTH(OrderDate)<EOMONTH(DATEADD(MONTH,-1,GETDATE())) -- check for month and year
AND C_ID NOT IN (
SELECT C_ID FROM [Order]
WHERE EOMONTH(OrderDate)=EOMONTH(DATEADD(MONTH,-1,GETDATE())) -- check for month and year
)
我认为使用变量
更有用DECLARE @lastMonth date=EOMONTH(DATEADD(MONTH,-1,GETDATE()))
SELECT
C_ID,
MONTH(OrderDate)
FROM [Order]
WHERE EOMONTH(OrderDate)<@lastMonth -- check for month and year
AND C_ID NOT IN (
SELECT C_ID FROM [Order]
WHERE EOMONTH(OrderDate)=@lastMonth -- check for month and year
)
没有子查询的变体
SELECT
C_ID,
MIN(OrderDate) FirstOrderDate,
MAX(OrderDate) LastOrderDate
FROM [Order]
WHERE OrderDate<=EOMONTH(DATEADD(MONTH,-1,GETDATE()))
GROUP BY C_ID
HAVING EOMONTH(MAX(OrderDate))<EOMONTH(DATEADD(MONTH,-1,GETDATE()))
或者
DECLARE @lastMonth date=EOMONTH(DATEADD(MONTH,-1,GETDATE()))
SELECT
C_ID,
MIN(OrderDate) FirstOrderDate,
MAX(OrderDate) LastOrderDate
FROM [Order]
WHERE OrderDate<=@lastMonth
GROUP BY C_ID
HAVING EOMONTH(MAX(OrderDate))<@lastMonth
但在这里我只返回MIN(OrderDate)
和MAX(OrderDate)
但也许它适合你。
我认为带有子查询的变体更糟糕。我认为它更清楚。
DECLARE @lastMonth date=EOMONTH(DATEADD(MONTH,-1,GETDATE()))
SELECT
C_ID,
YEAR(OrderDate) [Year],
MONTH(OrderDate) [Month]
COUNT(ID) OrderCount
FROM [Order]
WHERE EOMONTH(OrderDate)<@lastMonth
--AND YEAR(OrderDate)=YEAR(@lastMonth) -- if you need only orders from this year
AND C_ID IN(
SELECT DISTINCT C_ID
FROM [Order]
WHERE EOMONTH(OrderDate)=@lastMonth
)
GROUP BY C_ID,YEAR(OrderDate),MONTH(OrderDate)
答案 1 :(得分:0)
使用过时信息时,您不能只使用月份编号,因为第1个月是在第12个月(去年)之后。因此,使用日期,而不是月份数。
对于此查询,我们需要&#34;本月&#34;和#34;上个月&#34;按他们的日期(而不是月份数字),我们可以通过使用getdate()
开始一个有用的&#34;技巧&#34;这里是计算本月的第一天,我们可以通过计算从零datediff(month,0, getdate() )
开始的月数然后将该数字添加到零dateadd(month, ..., 0)
来完成。因此,一旦我们有了本月的第一个月,就可以通过减去或增加1个月来轻松计算上个月的第一个月和下个月的第一个月。
因此,对于可在任何版本的SQL Server中使用的解决方案:
MS SQL Server 2014架构设置:
CREATE TABLE Orders
([ID] int, [C_Id] int, [OrderDate] datetime)
;
INSERT INTO Orders
([ID], [C_Id], [OrderDate])
VALUES
(1, 1, '2017-05-12 00:00:00'),
(2, 2, '2017-12-12 00:00:00'),
(3, 3, '2017-11-12 00:00:00'),
(4, 4, '2017-12-12 00:00:00'),
(5, 1, '2017-12-12 00:00:00'),
(6, 2, '2017-12-12 00:00:00'),
(7, 3, '2017-12-12 00:00:00'),
(8, 4, '2017-11-12 00:00:00'),
(9, 2, '2017-06-12 00:00:00'),
(10, 3, '2017-07-12 00:00:00')
;
CREATE TABLE Customers
([Id] int, [Name] varchar(1))
;
INSERT INTO Customers
([Id], [Name])
VALUES
(1, 'A'),
(2, 'b'),
(3, 'c'),
(4, 'd'),
(5, '3'),
(6, 'f'),
(7, 'g')
;
查询1 :
declare @this_month datetime = dateadd(month, datediff(month,0, getdate() ), 0)
declare @last_month datetime = dateadd(month,-1,@this_month)
select
c.Id
, c.name
, count(case when o.OrderDate >= @last_month and o.OrderDate < @this_month then 1 end) last_month
, count(case when o.OrderDate >= @this_month then 1 end) this_month
from customers c
LEFT join orders o on c.id = o.c_id
and OrderDate >= @last_month
and OrderDate < dateadd(month,1,@this_month)
group by c.Id, c.name
having count(case when o.OrderDate >= @last_month and o.OrderDate < @this_month then 1 end) = 0
and count(case when o.OrderDate >= @this_month then 1 end) > 0
<强> Results 强>:
| Id | name | last_month | this_month |
|----|------|------------|------------|
| 1 | A | 0 | 1 |
| 2 | b | 0 | 2 |
declare @this_year datetime = dateadd(year, datediff(year,0, getdate() ), 0)
declare @this_month datetime = dateadd(month, datediff(month,0, getdate() ), 0)
declare @last_month datetime = dateadd(month,-1,@this_month)
select
c.Id
, c.name
, count(case when o.OrderDate >= @last_month and o.OrderDate < @this_month then 1 end) last_month
, count(o.OrderDate) this_year
from customers c
LEFT join orders o on c.id = o.c_id
and OrderDate >= @this_year
and OrderDate < dateadd(year,1,@this_year)
group by c.Id, c.name
having count(case when o.OrderDate >= @last_month and o.OrderDate < @this_month then 1 end) = 0
and count(o.OrderDate) > 0
;