GROUP BY日期范围?

时间:2012-03-12 11:55:34

标签: sql sql-server-2008 tsql stored-procedures

我有以下存储过程:

SELECT tsks.grouping_ref, ttg.description AS grouping_desc, 
SUM(ts.booked_time) AS booked_time_total, 
DATENAME(MONTH, ts.start_dtm) + ' ' + DATENAME(YEAR, ts.start_dtm) AS month_name,
@month_ref AS month_ref

FROM timesheets ts
JOIN timesheet_categories cat
ON ts.timesheet_cat_ref = cat.timesheet_cat_ref

JOIN timesheet_tasks tsks
ON ts.task_ref = tsks.task_ref

JOIN timesheet_task_groupings ttg
ON tsks.grouping_ref = ttg.grouping_ref

WHERE ts.status IN(1, 2) --Booked and approved
AND cat.is_leave_category = 0 --Ignore leave
--AND DATEPART(YEAR, ts.start_dtm) = @Year
--AND DATEPART(MONTH, ts.start_dtm) = @Month

--accounting months 2012
AND (@month_ref = 81201 AND ts.start_dtm Between '2011-11-28' AND '2012-01-01')
  or (@month_ref = 81202 AND ts.start_dtm Between '2012-01-02' AND '2012-01-29')
  or (@month_ref = 81203 AND ts.start_dtm Between '2012-01-30' AND '2012-02-26')
  or (@month_ref = 81204 AND ts.start_dtm Between '2012-02-27' AND '2012-04-01')
  or (@month_ref = 81205 AND ts.start_dtm Between '2012-04-02' AND '2012-04-29')
  or (@month_ref = 81206 AND ts.start_dtm Between '2012-04-30' AND '2012-05-27')
  or (@month_ref = 81207 AND ts.start_dtm Between '2012-05-28' AND '2012-06-01')
  or (@month_ref = 81208 AND ts.start_dtm Between '2012-07-02' AND '2012-07-29')
  or (@month_ref = 81209 AND ts.start_dtm Between '2012-07-30' AND '2012-08-26')
  or (@month_ref = 81210 AND ts.start_dtm Between '2012-08-27' AND '2012-09-30')
  or (@month_ref = 81211 AND ts.start_dtm Between '2012-10-01' AND '2012-10-28')
  or (@month_ref = 81212 AND ts.start_dtm Between '2012-10-29' AND '2012-11-25')


GROUP BY tsks.grouping_ref, ttg.description,
DATENAME(MONTH, ts.start_dtm),
DATENAME(YEAR, ts.start_dtm)
ORDER BY grouping_desc

基本上它根据日期范围过滤结果,然后将结果分组如下:

Job Group | Month  | Booked Hours

   Test   | Feb 12 |    7

然后,用户点击“测试”,他们将在预订的7小时内看到报告。 我想根据日期范围进行分组?

我知道这会创造月份:

DATENAME(MONTH, ts.start_dtm),
DATENAME(YEAR, ts.start_dtm)

但按日期范围的组只应出现是否有结果,即测试可能在1范围内,因此它会显示,否则不显示日期范围。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

我不明白你的问题。

看到

之后
AND (@month_ref = 81201 AND ts.start_dtm Between '2011-11-28' AND '2012-01-01')
  or (@month_ref = 81202 AND ts.start_dtm Between '2012-01-02' AND '2012-01-29')

我记得2年前我们的代码是怎么样的。您可以考虑将DatesTable添加到数据库中。在我们的网站上,我们存储自公司成立至今的所有日期以及未来20年的日期。每天都有许多属性(维度,列,无论你怎么称呼它们)IsWeekDay,IsHolliday,Quarter,YearNr,MonthNr,WeekNr,DayName,MonthName,......你可以添加你的业务所需的任何额外列。

只需将活动日期加入此表格,然后选择您需要的任何维度,例如季度和年份。您可以使用它们对结果进行分组。

我花了不到半天的时间向谷歌开始查询以填充此表。我们首先为我们的数据仓库做了这个,但是现在关于每个部门都在使用它来计算工作日,周六,周日,节假日工作的薪酬支票;基于周,月,年,季度的财务报告......

它简化了我们的查询。

答案 1 :(得分:2)

我仍然没有100%清楚你所追求的是什么。我会尽我所能。

我正在使用Dates表,其中包含您的公司使用的month_ref和month_name。如您所见,在填充Dates表后,它会保存您需要的日期周围的所有数据。在SELECT和GROUP部分中使用month_name。

注意使用Dates表后查询变得多么简单。

CREATE TABLE Dates(
  TheDate       DATE    NOT NULL,
  month_ref     INT     NOT NULL,
  month_name    VARCHAR(10)
) 

INSERT INTO Dates(TheDate, month_ref, month_name) VALUES
('20120312', 81204, 'March 2012')

DECLARE @month_ref INT
SET @month_ref = 81204

SELECT tsks.grouping_ref, 
  ttg.description AS grouping_desc, 
  SUM(ts.booked_time) AS booked_time_total, 
  Dates.MyDisplayValue AS month_name,
  Dates.month_ref AS month_ref
FROM timesheets ts
  JOIN timesheet_categories cat
    ON ts.timesheet_cat_ref = cat.timesheet_cat_ref
  JOIN timesheet_tasks tsks
    ON ts.task_ref = tsks.task_ref
  JOIN timesheet_task_groupings ttg
    ON tsks.grouping_ref = ttg.grouping_ref
  INNER JOIN Dates 
    ON ts.start_dtm = Dates.TheDate
WHERE ts.status IN(1, 2) --Booked and approved
  AND cat.is_leave_category = 0 --Ignore leave
  AND Dates.month_ref = @month_ref
GROUP BY tsks.grouping_ref, 
  ttg.description,
  Dates.MyDisplayValue,
  Dates.month_ref
ORDER BY grouping_desc

答案 2 :(得分:1)

我是第二个Wim所说的,因为它是完整的解决方案。如果您想要修补当前的问题,那么如果您创建一个范围及其名称,连接和按范围名称分组的表格会更好:

select dr.Name ...
 ...
inner join date_ranges dr
  on ts.start_dtm between dr.StartDate and dr.EndDate
  and dr.ID = @month_ref
 ...
group by dr.Name ...

这样您就不必每年更改查询,并保留以前查询的副本。

编辑:按范围分组

您希望在分组中重复过滤。您只过滤一个范围,因此您不需要分组。放入类似

的选择列表
case @month_ref when '81201' then '1 2012' when '81202' then '2 2012' etc end. 

如果你想要更通用的解决方案,请在case语句中检查start_dtm,如下所示:

case when start_dtm between ... then '1 2012' .... end. 

但是你必须在分组中重复它。我给你的第一个解决方案可以为你节省大量的复制粘贴和错误搜索。