我正在使用SQL Server Compact Edition服务器,我想计算每个月内与某个日期范围内的某个教程相对应的评论数量,并包括计数为零的月份。我知道我需要加入一个"日历"表到我的表,以说明缺少的月份,但我需要帮助正确实现这一点。
我有来自不同教程的所有评论的表格。此表称为评论,我需要的列是[Tutorial]
(nvarchar
)和[DateAdded]
(DateTime
)。
Tutorial | DateAdded
---------+-------------
sample | 2013-09-02
sample | 2013-09-04
sample | 2013-09-12
sample | 2013-09-12
example | 2013-09-15
sample | 2013-09-16
sample | 2013-09-21
sample | 2013-09-30
sample | 2013-10-01
sample | 2013-11-11
sample | 2013-11-11
example | 2013-11-14
sample | 2013-11-15
sample | 2013-11-19
sample | 2013-11-21
sample | 2013-11-25
sample | 2014-02-04
sample | 2014-02-06
我有一个Calendar
表,其中包含年份和月份列:
Year | Month
-----+------
2000 | 01
2000 | 02
. | .
. | .
. | .
2099 | 12
如果我正在寻找“'样本”的每月统计数据。过去一年的评论(截至2014年2月14日),那么理想的输出将是:
Tutorial | Year | Month | Count
---------+------+-------+------
sample | 2013 | 09 | 7
sample | 2013 | 10 | 1
sample | 2013 | 11 | 6
sample | 2013 | 12 | 0
sample | 2014 | 01 | 0
sample | 2014 | 02 | 2
我能够弄清楚如何进行以下查询,但我还需要没有注释的月份才能返回0。
SELECT
Tutorial,
datepart(year, DateAdded) AS Year,
datepart(month, DateAdded) AS Month,
COUNT(*) AS Count From Comments
WHERE
DateAdded > DATEADD(year,-1,GETDATE())
AND
Tutorial='sample'
GROUP BY
Tutorial,
datepart(year, DateAdded),
datepart(month, DateAdded)
使用上面的样本数据输出。
Tutorial | Year | Month | Count
---------+------+-------+------
sample | 2013 | 09 | 7
sample | 2013 | 10 | 1
sample | 2013 | 11 | 6
sample | 2014 | 02 | 2
我知道我需要加入表格,但我似乎无法弄清楚要使用哪个联接或如何正确实现它。请记住,这是针对SQL Server CE的,因此不能使用SQL Server中的所有命令。
提前非常感谢!
答案 0 :(得分:1)
如果您的Calendar
表格中包含Month
和Year
,那么您应尝试使用
SELECT t2.Tutorial, t1.[Month], t1.[Year], COALESCE(t2.Number, 0) AS Result
FROM Calendar AS t1 LEFT JOIN (
SELECT
Tutorial,
CONVERT(NCHAR(6), DateAdded, 112) AS tutDate,
COUNT(*) AS Count From Comments
WHERE
DateAdded > DATEADD(year,-1,GETDATE())
AND
Tutorial='sample'
GROUP BY
Tutorial,
CONVERT(NCHAR(6), [Order Date], 112)
) AS t2
ON (t1.[Year] + t1.[Month]) = t2.tutDate
ORDER BY t1.[Year] + t1.[Month]
答案 1 :(得分:0)
以下是一个独立的脚本,您可以使用它来尝试,而不是触及生产中的任何真实数据库对象。代码的底部三分之一包含您正在寻找的联接的帮助。
SQL Server CE允许您编写存储过程,而存储过程又可以用作报告的来源。存储过程很好,因为它们可以接受输入参数,这是进行报告的理想选择。
-- create dummy Comments table for prototyping
create table #Comments (
ID int identity(1,1) not null,
Tutorial nvarchar(50) not null,
DateAdded datetime not null,
primary key clustered(DateAdded,ID,Tutorial)
);
-- populate dummy Comments table
declare @startDate datetime = '2000-01-01';
declare @endDate datetime = '2014-02-14';
declare @numTxns int = 5000;
set nocount on;
declare @numDays int = cast(@endDate as int) - cast(@startDate as int) + 1;
declare @i int = 1;
declare @j int = @i + @numTxns;
declare @rnd float;
while @i <= @j
begin
set @rnd = RAND();
insert into #Comments (Tutorial,DateAdded)
select
-- random tutorial titles
coalesce (
case when @rnd < .25 then 'foo' else null end,
case when @rnd between .5 and .75 then 'baz' else null end,
case when @rnd > .75 then 'qux' else null end,
'bar'
) as Tutorial,
-- random dates between @startDate and @endDate
cast(cast(rand() * @numDays + @startDate as int) as datetime) as DateAdded
set @i = @i + 1
end;
-- try deleting some months to see what happens
delete from #Comments
where DateAdded between '2013-11-01' and '2013-11-30'
or DateAdded between '2014-01-01' and '2014-01-31';
set nocount off;
go
-- ### following could easily be rewritten as a stored procedure
-- stored procedure parameters
declare @startDate datetime = '2000-01-01';
declare @endDate datetime = '2014-03-31';
-- pick only one option below
--declare @Tutorial nvarchar(50) = 'foo'; -- this only gets data for Tutorials called 'foo'
declare @Tutorial nvarchar(50) = 'all'; -- this gets data for all tutorials
-- begin stored procedure code
set nocount on;
-- this temp table is an alternative to
-- creating ***and maintaining*** a table full of dates,
-- months, etc., and cluttering up your database
-- in production, it will automatically delete itself
-- once the user has completed running the report.
create table #dates (
DateAdded datetime not null,
YearAdded int null,
MonthAdded int null,
primary key clustered (DateAdded)
);
-- now we put dates into #dates table
-- based on the parameters supplied by
-- the user running the report
declare @date datetime = @startDate;
while @date <= @endDate
begin
insert into #dates
select @date, YEAR(@date), MONTH(@date);
set @date = @date + 1;
end;
-- ## Why put every day of the month in this table?
-- ## I asked for a monthy report, not daily!
-- Yes, but looping through dates is easier, simply add 1 for the next date.
-- You can always build a monthly summary table later if you'd like.
-- This *is* kind of a brute-force solution, but easy to write.
-- More answers to this question in the code below, where they'll make more sense.
set nocount off;
-- now we return the data to the user
-- any month with no Tutorials will still show up in the report
-- but the counts will show as zero
select YearAdded, MonthAdded, SUM(Count_From_Comments) as Count_From_Comments,
SUM(foo) as Count_Foo, SUM(bar) as Count_Bar,
SUM(baz) as Count_Baz, SUM(qux) as Count_Qux
from (
-- ## you can reuse the following code for a detail report by day
-- ## another answer to 'Why not by month?' from above
-- start daily report code
select t1.DateAdded, t1.YearAdded, t1.MonthAdded, t2.Tutorial,
coalesce(Count_From_Comments,0) as Count_From_Comments,
case when t2.Tutorial = 'foo' then 1 else 0 end as foo,
case when t2.Tutorial = 'bar' then 1 else 0 end as bar,
case when t2.Tutorial = 'baz' then 1 else 0 end as baz,
case when t2.Tutorial = 'qux' then 1 else 0 end as qux
from #dates as t1 -- no where clause needed because #dates only contains the ones we want
left join ( -- left join here so that we get all dates, not just ones in #Comments
select *, 1 AS Count_From_Comments
from #Comments
where @Tutorial in (Tutorial,'all')
) as t2
on t1.DateAdded = t2.DateAdded -- ## join on one field instead of two, another answer to 'Why not by month?' from above
-- end daily report code
) as qDetail
group by YearAdded, MonthAdded
order by YearAdded, MonthAdded
-- end stored procedure code
go
-- ## Not required in production code,
-- ## but handy when testing this script.
drop table #dates;
-- #### Since this will be a real table in production
-- #### we definitely only want this for testing!
drop table #Comments;
go
快乐的编码。