Database 按年份和月份计数记录,包括零计数
我使用的是SQL Server Compact Edition服务器,我想计算在一定日期范围内每月与某个教程相对应的评论数,包括计数为零的月份。我知道我需要将一个“日历”表加入到我的表中,以说明缺少的月份,但我需要帮助正确实现这一点 我有一个表格,里面有来自不同教程的所有评论。此表称为注释,我需要的列是Database 按年份和月份计数记录,包括零计数,database,join,count,sql-server-ce,webmatrix,Database,Join,Count,Sql Server Ce,Webmatrix,我使用的是SQL Server Compact Edition服务器,我想计算在一定日期范围内每月与某个教程相对应的评论数,包括计数为零的月份。我知道我需要将一个“日历”表加入到我的表中,以说明缺少的月份,但我需要帮助正确实现这一点 我有一个表格,里面有来自不同教程的所有评论。此表称为注释,我需要的列是[Tutorial](nvarchar)和[DateAdded](DateTime) 我有一个日历表,它有一个年和月列,如下所示: Year | Month -----+------ 2000 |
[Tutorial]
(nvarchar
)和[DateAdded]
(DateTime
)
我有一个日历
表,它有一个年和月列,如下所示:
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的命令都可以使用
非常感谢 下面是一个独立的脚本,您可以使用它进行尝试,而不必在生产环境中接触任何真实的数据库对象。代码的下三分之一包含您正在寻找的连接的帮助 SQLServerCE将允许您编写存储过程,而存储过程又可以用作报表的源。存储的进程很好,因为它们可以接受输入参数,这是执行报告的理想选择
-- 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
——为原型创建虚拟注释表
创建表#注释(
ID int标识(1,1)不为空,
教程nvarchar(50)不为空,
DateAdded datetime不为空,
主键群集(已添加日期、ID、教程)
);
--填充虚拟注释表
声明@startDate datetime='2000-01-01';
声明@endDate datetime='2014-02-14';
声明@numTxns int=5000;
不计数;
声明@numDays int=cast(@endDate为int)-cast(@startDate为int)+1;
声明@i int=1;
声明@j int=@i+@numTxns;
宣布@rnd浮动;
而@i.75然后'qux'则为空端,
“酒吧”
)作为教程,
--@startDate和@endDate之间的随机日期
强制转换(强制转换(rand()*@numDays+@startDate为int)为datetime)为DateAdded
设置@i=@i+1
结束;
--尝试删除几个月,看看会发生什么
从#注释中删除
其中日期添加在“2013-11-01”和“2013-11-30”之间
或在“2014-01-01”和“2014-01-31”之间添加的日期;
不计数;
去
--######以下内容可以很容易地重写为存储过程
--存储过程参数
声明@startDate datetime='2000-01-01';
声明@endDate datetime='2014-03-31';
--只选择下面的一个选项
--声明@Tutorial nvarchar(50)=“foo”;--这只获取名为“foo”的教程的数据
声明@Tutorial nvarchar(50)=“全部”;--这将获取所有教程的数据
--开始存储过程代码
不计数;
--此临时表是一个替代表
--创建***并维护***一个充满日期的表格,
--几个月等等,把你的数据库弄得乱七八糟
--在生产中,它将自动删除自身
--一旦用户完成报告的运行。
创建表#日期(
DateAdded datetime不为空,
YearAdded int null,
蒙塔德整数为空,
主键群集(已添加日期)
);
--现在我们将日期放入#dates表中
--根据制造商提供的参数
--运行报表的用户
声明@date datetime=@startDate;
而@date如果你有一个日历
表格,上面有月
和年
,你应该尝试以下方法
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]
这些都不适用于SQL CE
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]