我有以下查询,日期范围介于' 09/01/16 '和' 12/30/16 '。在附图中,结果仅适用于 9月和 10月,我仍希望显示 11月和 12月(或计数 0
的给定date2
范围
我该如何做到这一点?
declare @date1 date = '09/01/16'
declare @date2 date = '12/30/16'
select
count(distinct w.wkid) as WksCount
,DATENAME(MONTH, r.date) as [month]
,year(r.date) as [year]
from
Workshop w
left join Reservation r on r.wkid=w.wkid
left join Registration reg on reg.wkid=w.wkid
where
r.date between @date1 and @date2
group by
DatePart(Month, r.date)
,DateName(Month, r.date)
,year(r.date)
order by
year(r.date)
,DatePart(Month, r.date)
我
答案 0 :(得分:1)
稍微不同 - 我认为更容易理解和理解 - 方法,您可以使用CTE
构建您的日期表并从中加入以获取完整的月份列表。
我已在cte
中指定了月初和月末,因此您可以join
从on
开始,而无需使用r.date
条件中的功能如果您的Workshop表很大,则会触发,因为这些函数会禁止索引利用。
如果您的datetime
字段为declare @date1 date = '20160801';
declare @date2 date = '20161231';
with Dates
as
(
select dateadd(m,datediff(m,0,@date1),0) as MonthStart
,dateadd(d,-1,dateadd(m,datediff(m,0,@date1)+1,0)) as MonthEnd
union all
select dateadd(m,1,MonthStart)
,dateadd(d,-1,dateadd(m,2,MonthStart))
from Dates
where MonthStart < dateadd(m,datediff(m,0,@date2),0)
)
select
count(distinct w.wkid) as WksCount
,DATENAME(MONTH, d.MonthStart) as [month]
,year(d.MonthStart) as [year]
from Dates d
left join Reservation r on r.date between d.MonthStart and d.MonthEnd
and r.date between @date1 and @date2
left join Workshop w on r.wkid=w.wkid
left join Registration reg on reg.wkid=w.wkid
group by
DatePart(Month, r.date)
,DateName(Month, r.date)
,year(r.date)
order by
year(r.date)
,DatePart(Month, r.date);
,则需要调整以下值以处理该月最后一天的最后一毫秒的值:
<a id="createCampaignBtn" data-target="#createCampaignModal" data-toggle="modal"
class="removeRight removeLeft buttonsA">
<div class="buttons removeRight centerTextOutHoriz">
<span class="centerTextInner buttonRight">Start a new Campaign</span>
</div>
</a>
答案 1 :(得分:0)
这是Sean Lange所建议的主旨。
因此,没有数据的月份除了月份数之外,每列中只有一条记录为空。 现在要使用月份名称而不是月份编号,请参阅this question以了解具体方法。
P.S:月份数是Tally.N
declare @date1 date = '09/01/16'
declare @date2 date = '12/30/16'
--1: Build a tally table with CTE
;WITH
N0(_) AS (SELECT NULL UNION ALL SELECT NULL),
N1(_) AS (SELECT NULL FROM N0 AS L CROSS JOIN N0 AS R),
Tally AS (SELECT N = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM N1 AS L CROSS JOIN N1 AS R)
--2: Select data using the tally
select
count(distinct w.wkid) as WksCount
,Tally.N as [monthNo]
from Tally,
LEFT JOIN Reservation AS r ON Tally.N = DATEPART(MONTH, r.date)
AND r.date >= @date1
AND r.daye <= @date2
LEFT JOIN Workshop AS w ON r.wkid = w.wkid
left join Registration AS reg ON w.wkid = reg.wkid
WHERE Tally.N >= DATEPART(MONTH, @date1)
AND Tally.N <= DATEPART(MONTH, @date2)
GROUP BY
Tally.N --N is the month number
ORDER BY
Tally.N
答案 2 :(得分:0)
对于使用表变量作为“基表”的非常大的结果表来说更容易:
--add these lines before your select
declare @d datetime set @d=@date1
declare @t table(count int, month varchar(12), year int)
--fill the table with 0-month-year values
while @d < @date2
begin
insert into @t values(0, datename(mm, @d), datepart(yy, @d))
set @d = dateadd(mm, 1, @d)
end
然后将结果添加到表变量:
insert into @t
select count(distinct w.wkid)
,DATENAME(MONTH, r.date)
,year(r.date)
from Workshop w
left join Reservation r on r.wkid=w.wkid
left join Registration reg on reg.wkid=w.wkid
where r.date between @date1 and @date2
group by DatePart(Month, r.date) ,DateName(Month, r.date), year(r.date)
最后获得所需的结果:
select sum(count) as count, month, year from @t
group by year, month
order by year desc, month desc
来自相对较少的表变量的聚合查询比另一个LEFT JOIN便宜得多。如果你有很多句号,可以考虑使用#temporary table。
抱歉,我现在没有安装MSSqlServer来检查我的代码,但这个想法非常简单。