我需要编写一个接受开始日期,结束日期和频率(日,周,月,季,年)的存储过程,并根据这些参数输出结果集。显然,简单的部分是按日期范围查询,但是如何按频率分组?
所以,如果有一组这样的原始数据:
Date Count
---------------------
11/15/2011 6
12/16/2011 9
12/17/2011 2
12/18/2011 1
12/18/2011 4
我将这样的存储过程称为:
sp_Report' 1/1/2011',' 12/31/2011','周'
我希望这样的结果:
WeekOf Count
---------------------
11/19/2011 6
12/17/2011 11
12/24/2011 5
这里有几个问题:
1)如何确定一周结束的日期(周日结束的一周)?
2)如何按WeekOf日期范围进行分组?
答案 0 :(得分:10)
以下脚本以统一的方式表示输出:它显示期间的开始和结束日期以及期间的总计数。
这也确定了寻找分组值的方法。基本上,您可以看到三种不同的模式:一种用于'day'
频率,另一种用于'week'
,另一种用于所有其他频率类型。
第一个是最简单的:PeriodStart和PeriodEnd都只是Date
。
几个星期以来,我正在使用一个众所周知的技巧,即一周的第一天是从给定日期派生的,减去一个比工作日数少一个的值。类似的结尾也是如此:我们只是将6
添加到同一个表达式中。
月,季度和年份按以下方式分组。零日期和给定日期之间的相应单位的整数数量被添加回零日期。这给了我们这个时期的开始。结果非常相似,只有我们添加的数字大于差值。这会产生 next 期间的开始,因此我们将减去一天,这样就可以得到正确的结束日期。
SELECT
PeriodStart,
PeriodEnd,
Count = SUM(Count)
FROM (
SELECT
PeriodStart = CASE @Frequency
WHEN 'day' THEN Date
WHEN 'week' THEN DATEADD(DAY, 1 - DATEPART(WEEKDAY, Date), Date)
WHEN 'month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)
WHEN 'quarter' THEN DATEADD(QUARTER, DATEDIFF(QUARTER, 0, Date), 0)
WHEN 'year' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, Date), 0)
END,
PeriodEnd = CASE @Frequency
WHEN 'day' THEN Date
WHEN 'week' THEN DATEADD(DAY, 7 - DATEPART(WEEKDAY, Date), Date)
WHEN 'month' THEN DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, Date) + 1, 0))
WHEN 'quarter' THEN DATEADD(DAY, -1, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, Date) + 1, 0))
WHEN 'year' THEN DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, Date) + 1, 0))
END,
Count
FROM atable
WHERE Date BETWEEN @DateStart AND @DateEnd
) s
GROUP BY
PeriodStart,
PeriodEnd
EXEC spReport '1/1/2011', '12/31/2011', 'day'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-11-15 2011-11-15 6
2011-12-16 2011-12-16 9
2011-12-17 2011-12-17 2
2011-12-18 2011-12-18 5
EXEC spReport '1/1/2011', '12/31/2011', 'week'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-11-13 2011-11-19 6
2011-12-11 2011-12-17 11
2011-12-18 2011-12-24 5
EXEC spReport '1/1/2011', '12/31/2011', 'month'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-11-01 2011-11-30 6
2011-12-01 2011-12-31 16
EXEC spReport '1/1/2011', '12/31/2011', 'quarter'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-10-01 2011-12-31 22
EXEC spReport '1/1/2011', '12/31/2011', 'year'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-01-01 2011-12-31 22
注意:来自MSDN:
在命名过程时避免使用 sp _ 前缀。 SQL Server使用此前缀来指定系统过程。如果存在具有相同名称的系统过程,则使用前缀可能导致应用程序代码中断。有关详细信息,请参阅Designing Stored Procedures (Database Engine)。
答案 1 :(得分:0)
Create procedure MyProc
@startDate DateTime,
@endDate DateTime,
@freq varChar(5)
As
If @freq = "day"
Select DateAdd(day, 0, datediff(day, 0, date)), Frequency,
Sum(Count)
From Table
Group By DateAdd(day, 0, datediff(day, 0, date))
Else If @freq = "week"
Select DateAdd(week, 0, datediff(week, 0, date)), Frequency,
Sum(Count)
From Table
Group By DateAdd(week, 0, datediff(week, 0, date))
Else If @freq = "Month"
Select DateAdd(Month, 0, datediff(Month, 0, date)), Frequency,
Sum(Count)
From Table
Group By DateAdd(Month, 0, datediff(Month, 0, date))
Else If @freq = "Quarter"
Select DateAdd(Quarter, 0, datediff(Quarter, 0, date)), Frequency,
Sum(Count)
From Table
Group By DateAdd(Quarter, 0, datediff(Quarter, 0, date))
Else If @freq = "Year"
Select DateAdd(Year, 0, datediff(Year, 0, date)), Frequency,
Sum(Count)
From Table
Group By DateAdd(Year, 0, datediff(Year, 0, date))
答案 2 :(得分:0)
这样的事情应该有效。
select date_column,
sum(count)
from @table
where date_column between @start_date and @end_date
group by case @frequency
when 'week' then datepart(week,date_column )
when 'year' then datepart(year,date_column)
when 'quarter' then datepart(quarter,date_column)
when ...
end;
答案 3 :(得分:0)
select `date` as weekOf, sum(amt)
from myTable
where `date` between '2011-10-01' and '2012-01-01'
group by week(`date` )