使用T-SQL查找在特定年份的任何ISO周内完成的订单

时间:2010-12-13 22:28:18

标签: sql sql-server tsql

作为报告设置的一部分,我有一个SQL查询来获取每周下达的订单数量:

select datepart(isowk, order_date), count(*)
from orders where year(order_date) = @Year
group by datepart(isowk, order_date), year(order_date)
order by 1

请注意,我在isowk函数调用中使用了新的datepart格式,因为丹麦的商家通常使用ISO周数。

使用@Year = 2010运行此查询会产生一个结果集simialar:

1           5
2           7
3           10
...
53          3

你和我都知道2010年还没有结束,当然还没有第53周。实际上,有一年 - 前三天属于ISO 2009年第53周。尽管可能向其他程序员解释这一点,但是想要阅读我的报告的人永远不会理解这一点。因此,我希望通过将数据“移动”到2009年来摆脱本周53.

如何重写我的WHERE子句,将数据集过滤为定义为@Year的第1周的星期一和上周的星期五(52或53)之间的订单?< / p>

5 个答案:

答案 0 :(得分:2)

事实上,我不知道任何提供isoyear的编程语言......

create function isoyear(@date datetime) returns smallint as begin
declare @isoyear smallint =
    case
    when datepart(isowk, @date) = 1 and month(@date) = 12
    then year(@date)+1
    when datepart(isowk, @date) = 53 and month(@date) = 1
    then year(@date)-1
    else year(@date)
    end;
return @isoyear;
end;

希望下次我们能得到一个datepart(isoyear,......)......

答案 1 :(得分:1)

你可以试试这个:

set datefirst 1;

declare @Year smallint = 2010;

declare @DayInFirstWeek datetime = cast(@Year as varchar)+'0104';
declare @FirstDayInFirstWeek datetime = 
             @DayInFirstWeek - datepart(dw,@DayInFirstWeek)+1
declare @DayInFirstWeekNextYear datetime = cast(@Year+1 as varchar)+'0104';
declare @LastDayInLastWeek datetime = 
             @DayInFirstWeekNextYear - datepart(dw,@DayInFirstWeekNextYear);

select datepart(isowk, order_date), count(*) 
from orders
where order_date between @FirstDayInFirstWeek and @LastDayInLastWeek
group by datepart(isowk, order_date)
order by 1;

如果您一周的第一天不是星期一,那么它可能无效!

答案 2 :(得分:0)

执行IF语句 - 我不保证SQL服务器语法,但是:

// IF ISO week is 53, return week 1 of next year. 
GROUP BY IF(datepart(isowk, order_date)) = 53,
  CONCAT("1/", year(order_date) + 1),
  CONCAT(datepart(isowk, order_date), "/", year(order_date))

答案 3 :(得分:0)

我将使用我对Manfred's answer的评论中描述的方法自行尝试。我们的想法是找到指定年份和第一年的第一个ISO周的第一天,允许对输入记录进行索引启用between过滤。

首先,我创建一个函数,它将找到特定年份第一个ISO周的第一天:

create function firstIsoDay(@year int) returns datetime as begin
    declare @first datetime
    select @first = cast(cast(@year as char(4)) as datetime)
    select @first = dateadd(ww, datediff(ww, 0, @first), 0)
    if datepart(isowk, @first) > 1 set @first = @first + 7
    return @first
end

免责声明:此功能未经测试(目前没有可用的Sql Server 2008)。

然后可以在between过滤器中使用此函数的两次调用来进行实际数据查询:

select datepart(isowk, order_date), count(*) from orders
where order_date between firstIsoDay(@Year) and firstIsoDay(@Year + 1)
group by datepart(isowk, order_date), year(order_date)
order by 1

请记住,between是双向的。如果order_date中的值包含截断日期(没有时间),则应将-1添加到where子句的末尾。在我的用例中,order_date包含日期和时间,所以在午夜的两个日期之间应该没问题。

答案 4 :(得分:0)

这里只是说出基本答案:

如果您根据ISO周查询,必须根据ISO年度(而非日历年)进行过滤

如何为您的数据(或where子句)添加ISO年份列与其他人描述的一样。