我想要一个查询来返回不存在的行的值,以帮助制定统计信息查询..我相信最简单的分享样本..这是我的超小样本日期集:
category date ID
Swimming 2013-02-09 1
Hiking 2013-05-01 2
Archery 2013-07-03 3
Swimming 2013-08-05 4
Swimming 2013-08-22 5
Archery 2013-09-01 6
Swimming 2013-09-18 7
NULL 2013-09-19 8
我现在的查询:
DECLARE @startdate DATETIME = '04/01/2013'
DECLARE @enddate DATETIME = '10/31/2013'
DECLARE @activitycategory VARCHAR(40) = 'Swimming'
SELECT category AS 'Activity'
,CASE WHEN category is null THEN 'No Category'
ELSE category
END as ActivityCategory
,DATEPART(yyyy,date) AS 'Year'
,DATEPART(mm,date) AS 'Month'
,COUNT(ID) AS 'Total Activities'
FROM classes
WHERE date BETWEEN @startdate AND @enddate
AND category IN (@activitycategory)
GROUP BY category
,DATEPART(yyyy,date)
,DATEPART(mm,date)
ORDER BY category
,DATEPART(yyyy,date)
,DATEPART(mm,date)
我的查询目前产生以下结果:
Activity ActivityCategory Year Month Total Activities
Swimming Swimming 2013 8 2
Swimming Swimming 2013 9 1
我想要以下结果:
Activity ActivityCategory Year Month Total Activities
Swimming Swimming 2013 4 0
Swimming Swimming 2013 5 0
Swimming Swimming 2013 6 0
Swimming Swimming 2013 7 0
Swimming Swimming 2013 8 2
Swimming Swimming 2013 9 1
Swimming Swimming 2013 10 0
我做了很多研究,似乎我需要使用递归CTE ..我发现了一个“日期范围”功能,我认为显然是必要的(在有一个日历表之外)..我只是无法想象如何编写最终查询..正如您将注意到我的查询需要具有参数...(最终这将是一个SSRS报告)..无论用户选择什么,没有行返回的计数将产生一个如果在参数选择的日期范围内不存在“总活动”,则为“0”..任何帮助表示赞赏..这里是我发现的功能:
CREATE FUNCTION [dbo].[DateRange]
(
@Increment CHAR(1),
@StartDate DATETIME,
@EndDate DATETIME
)
RETURNS
@SelectedRange TABLE
(IndividualDate DATETIME)
AS
BEGIN
;WITH cteRange (DateRange) AS (
SELECT @StartDate
UNION ALL
SELECT
CASE
WHEN @Increment = 'd' THEN DATEADD(dd, 1, DateRange)
WHEN @Increment = 'w' THEN DATEADD(ww, 1, DateRange)
WHEN @Increment = 'm' THEN DATEADD(mm, 1, DateRange)
END
FROM cteRange
WHERE DateRange <=
CASE
WHEN @Increment = 'd' THEN DATEADD(dd, -1, @EndDate)
WHEN @Increment = 'w' THEN DATEADD(ww, -1, @EndDate)
WHEN @Increment = 'm' THEN DATEADD(mm, -1, @EndDate)
END)
INSERT INTO @SelectedRange (IndividualDate)
SELECT DateRange
FROM cteRange
OPTION (MAXRECURSION 3660);
RETURN
END
GO
提前致谢!
答案 0 :(得分:1)
我将假设无论用户输入什么,您都需要查看整个月
因为我仍然想要一个有效的约会而且我将无视这一天我将使用第一个,因为每个月都有一个月的第一天。
显然,如果您决定使用日期表,则可以将其替换为递归CTE(r_cte)
在您的脚本中尝试使用IN(@category)作为过滤器表达式, 我刚刚使用了=因为我们没有将列值与可能值列表进行比较
declare @data table (category varchar(10),activity_date datetime, ID int)
insert into @data values ('Swimming','2013-02-09',1)
insert into @data values ('Hiking','2013-05-01',2)
insert into @data values ('Archery','2013-07-03',3)
insert into @data values ('Swimming','2013-08-05',4)
insert into @data values ('Swimming','2013-08-22',5)
insert into @data values ('Archery','2013-09-01',6)
insert into @data values ('Swimming','2013-09-18',7)
insert into @data values (NULL,'2013-09-19',8)
declare @date_start datetime = '20130414'
declare @date_end datetime = '20131031'
declare @activity_category varchar(10) = 'Swimming'
set @date_start = dateadd(day,-(datepart(day,@date_start)-1),@date_start)
set @date_end = dateadd(day,-(datepart(day,@date_end)-1),@date_end)
;with r_cte
as (select @date_start as activity_period
union all
select dateadd(month, 1, activity_period)
from r_cte
where activity_period < @date_end
)
select
isnull(category,@activity_category) as Activity ,
isnull(category,@activity_category) as ActivityCategory,
DATEPART(MONTH,activity_period) as ActivityMonth,
DATEPART(YEAR,activity_period) as ActivityYear,
datename(month,activity_period) + ' ' + convert(varchar(4),datepart(year,activity_period)) as ActivityPeriod,
count(category) as TotalActivities
from r_cte r
left join
(select
dateadd(day,-(datepart(day,activity_date)-1),activity_date) as compare_date,
isnull(category,'No Category') as category
from @data
where category = @activity_category) d
on d.compare_date = r.activity_period
group by category, activity_period
order by r.activity_period