我目前有以下查询:
select
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0) as MonthYear, count(*) as Count
from
visit
where
StartDate >= DATEADD(year,-1,GETDATE())
and clientid = 142
group by
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0)
返回以下结果:
+-------------------------+----+
| 2015-12-01 00:00:00.000 | 1 |
| 2016-02-01 00:00:00.000 | 13 |
| 2016-03-01 00:00:00.000 | 1 |
| 2016-04-01 00:00:00.000 | 22 |
| 2016-05-01 00:00:00.000 | 22 |
| 2016-06-01 00:00:00.000 | 25 |
| 2016-07-01 00:00:00.000 | 36 |
+-------------------------+----+
我还有以下查询:
SELECT TOP (12)
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - test, 0) as MonthYear
FROM
test
返回以下结果:
+-------------------------+
| 2016-10-01 00:00:00.000 |
| 2016-09-01 00:00:00.000 |
| 2016-08-01 00:00:00.000 |
| 2016-07-01 00:00:00.000 |
| 2016-06-01 00:00:00.000 |
| 2016-05-01 00:00:00.000 |
| 2016-04-01 00:00:00.000 |
| 2016-03-01 00:00:00.000 |
| 2016-02-01 00:00:00.000 |
| 2016-01-01 00:00:00.000 |
| 2015-12-01 00:00:00.000 |
| 2015-11-01 00:00:00.000 |
+-------------------------+
我需要做的是将两个查询合并为一个查询,并针对原始查询中缺少的月份显示 0 。
有人可以帮忙吗?
答案 0 :(得分:3)
传统上这是通过日历表(例如this msdn answer)解决的,但在您的情况下,派生表和外连接应该有效:
select DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0) as MonthYear,count(*) as Count
from (SELECT TOP (12) DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-test, 0) as MonthYear
from test) cal LEFT OUTER JOIN visit on (cal.MonthYear = visit.MonthYear)
where StartDate >= DATEADD(year,-1,GETDATE())
and clientid = 142
group by DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0)
答案 1 :(得分:1)
此方法使用CROSS APPLY和VALUES创建主月份列表。
如果可以的话,我建议用变量替换GETDATE()。
CREATE TABLE #Visit(StartDate DATE,clientid int)
INSERT INTO #Visit VALUES
('20160304',142)
,('20160305',142)
,('20160508',142)
,('20160612',142)
,('20160617',142)
SELECT
T.Mnth
,COUNT(V.StartDate) AS [Count]
FROM
(VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) c (test)
CROSS APPLY (SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - c.test, 0) Mnth) T
LEFT JOIN #Visit V
ON
DATEDIFF(MM,V.startdate,T.Mnth) = 0
AND StartDate >= DATEADD(year,-1,GETDATE())
AND clientid = 142
GROUP BY
T.Mnth
ORDER BY
T.Mnth DESC
答案 2 :(得分:0)
有LEFT JOIN
和ISNULL
的几个子查询应该这样做:
SELECT sub1.MonthYear,
ISNULL(sub2.Count, 0)
FROM
(SELECT TOP (12) DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - test, 0) AS MonthYear
FROM test t) sub1
LEFT JOIN
(SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0) as MonthYear,
COUNT(*) AS Count
FROM visit
WHERE StartDate >= DATEADD(year,-1,GETDATE())
AND clientid = 142
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0)) sub2
ON sub1.MonthYear = sub2.MonthYear
答案 3 :(得分:0)
如果您要进行大量的差距和岛屿计算以及基于日期的查询而没有差距,那么我无法强调日历表会让您的生活变得多么简单。
基本上,您只需要一张类似于:
的表格<强>日历强>
Day INT,
Month INT,
Year INT,
StartOfDay DATETIME,
EndOfDay DATETIME,
DayOfWeek INT,
WeekInyear INT,
IsWeekDay BIT
选择日期范围。我选择了本世纪和上世纪,因为它符合我的商业模式需求。接下来,只需运行一次循环函数并填充表格,最后应用适当的索引并根据需要使用。
DECLARE @BeginDate DATETIME ='01/01/2015'
DECLARE @EndDate DATETIME ='01/01/2017'
DECLARE @MONTHS TABLE(Month INT,Year INT)
WHILE @BeginDate<=@EndDate BEGIN
INSERT @Months SELECT DATEPART(MONTH,@BeginDate),DATEPART(YEAR,@BeginDate)
SET @BeginDate=DATEADD(MONTH,1,@BeginDate)
END
SELECT
Calendar.Month,
Calendar.Year,
COUNT(visit.userID)
FROM
@Months Calendar
LEFT JOIN visit ON visit.year=Calendar.Year AND visit.Month=Calendar.Month
GROUP BY
Calendar.Month,
Calendar.Year
答案 4 :(得分:0)
我经常使用TVF创建动态日期/时间范围。这个udf比递归cte方法更快(特别是在较大的集合上)。此外,您还可以定义日期范围,日期部分和增量。我应该注意,一个计数表也可以做到这一点。
-- Generate Some Sample Data
Declare @Visit table (StartDate date,Cnt int)
Insert Into @Visit values
('2015-12-01 00:00:00.000', 1),
('2016-02-01 00:00:00.000',13),
('2016-03-01 00:00:00.000', 1),
('2016-04-01 00:00:00.000',22),
('2016-05-01 00:00:00.000',22),
('2016-06-01 00:00:00.000',25),
('2016-07-01 00:00:00.000',36)
-- Set Key Dates
Declare @DateR2 date = '2016-10-01'
Declare @DateR1 date = DateAdd(YY,-1,@DateR2)
-- Execute Query
Select DateR1
,Cnt = isnull(sum(Cnt),0)
From (Select DateR1=RetVal,DateR2=DateAdd(MM,1,RetVal)-1 From [dbo].[udf-Range-Date](@DateR1,@DateR2,'MM',1)) A
Left Join @Visit B on B.StartDate Between A.DateR1 and A.DateR2
Group By DateR1
Order by DateR1
返回
Period Cnt
2015-10-01 0
2015-11-01 0
2015-12-01 1
2016-01-01 0
2016-02-01 13
2016-03-01 1
2016-04-01 22
2016-05-01 22
2016-06-01 25
2016-07-01 36
2016-08-01 0
2016-09-01 0
2016-10-01 0
UDF(如果需要)
CREATE FUNCTION [dbo].[udf-Range-Date] (@R1 datetime,@R2 datetime,@Part varchar(10),@Incr int)
Returns Table
Return (
with cte0(M) As (Select 1+Case @Part When 'YY' then DateDiff(YY,@R1,@R2)/@Incr When 'QQ' then DateDiff(QQ,@R1,@R2)/@Incr When 'MM' then DateDiff(MM,@R1,@R2)/@Incr When 'WK' then DateDiff(WK,@R1,@R2)/@Incr When 'DD' then DateDiff(DD,@R1,@R2)/@Incr When 'HH' then DateDiff(HH,@R1,@R2)/@Incr When 'MI' then DateDiff(MI,@R1,@R2)/@Incr When 'SS' then DateDiff(SS,@R1,@R2)/@Incr End),
cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
cte3(N,D) As (Select 0,@R1 Union All Select N,Case @Part When 'YY' then DateAdd(YY, N*@Incr, @R1) When 'QQ' then DateAdd(QQ, N*@Incr, @R1) When 'MM' then DateAdd(MM, N*@Incr, @R1) When 'WK' then DateAdd(WK, N*@Incr, @R1) When 'DD' then DateAdd(DD, N*@Incr, @R1) When 'HH' then DateAdd(HH, N*@Incr, @R1) When 'MI' then DateAdd(MI, N*@Incr, @R1) When 'SS' then DateAdd(SS, N*@Incr, @R1) End From cte2 )
Select RetSeq = N+1
,RetVal = D
From cte3,cte0
Where D<=@R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1)
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1)
*/
答案 5 :(得分:0)
;with cteCalendar as
(
SELECT TOP (12)
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - test, 0) as MonthYear
FROM
test
),
cteVisits as
(
select
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0) as MonthYear, count(*) as Count
from
visit
where
StartDate >= DATEADD(year,-1,GETDATE())
and clientid = 142
group by
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0)
)
SELECT
c.MonthYear,
ISNULL(v.Count, 0) as VisitCount
FROM cteCalendar c
LEFT JOIN cteVisits v
ON v.MonthYear = c.MonthYear
ORDER BY c.MonthYear
答案 6 :(得分:0)
所以有很多关于如何创建MONTH表的答案和好的,然后请加入您的访问以获得答案。但我只是想告诉你,如果访问表中每个月至少有一个日期,条件聚合可以如何帮助你。注意,我不是指您要过滤的客户端的1条记录,而是指任何/所有客户端的记录。换句话说,每个月至少会有一个客户?如果是这样,你可以做条件聚合来得到这样的答案:
select
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0) as MonthYear
,count(CASE WHEN clientid = 142 THEN clientid END) as Count
from
visit
where
StartDate >= DATEADD(year,-1,GETDATE())
group by
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0)
如果没有,那么你需要一个日期表@pacreely向你展示一个很好的方法。
答案 7 :(得分:0)
您可以按如下方式格式化查询
;with CTE AS (select
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0) as MonthYear, count(*) as Count
from
visit
where
StartDate >= DATEADD(year,-1,GETDATE())
and clientid = 142
group by
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0)
)
, cte2 AS(
SELECT TOP (12)
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - test, 0) as MonthYear
FROM
test )
SELECT ISNULL(cte.MonthYear, cte2.MonthYear) AS MonthYear , ISNULL(cte.Count, 0) as Count
from cte FULL OUTER join cte2 on cte.MonthYear = cte2.MonthYear
答案 8 :(得分:-1)
declare @Dates table(date datetime, count int)
select
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0) as MonthYear, count(*) as Count
into @Dates
from
visit
where
StartDate >= DATEADD(year,-1,GETDATE())
and clientid = 142
group by
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0)
SELECT TOP (12)
into @Dates
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - test, 0) as MonthYear,0
FROM
test
select * from @Dates
答案 9 :(得分:-1)
在假设“测试”表是一个表,列出了至少过去一年的每个月的第一个月,并且可能还包括未来的日期,这是我的建议:
With VisitList as
(SELECT
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0) as MonthYear, count(*) as VisitCount
FROM visit
WHERE
StartDate >= DATEADD(year,-1,GETDATE())
and clientid = 142
GROUP BY
DATEADD(MONTH, DATEDIFF(MONTH, 0, StartDate), 0)
UNION
SELECT testDate, 0 AS VisitCount
FROM test
WHERE testDate BETWEEN DATEADD(YEAR, -1, GETDATE()) AND GETDATE())
SELECT MonthYear, Sum(VisitCount) AS VisitCount FROM VisitList
GROUP BY MonthYear
ORDER BY MonthYear DESC