2

我有一组 8 个月左右的数据,部分是 2012 年的数据,部分是 2013 年的数据。我不确定这是否是一种文化问题,但我是荷兰人,我相信数据库中的数据应该按照这个标准来解释。

所以我写了两个查询,一个使用常规周表达式,一个使用 ISO_week,这个查询看起来像这样:

SELECT datepart(ISO_WEEK,date_dtm) as date_detail,
datepart(yyyy,date_dtm) as date_year, 
(sum(sum_value)/sum(user_count)) as value 

FROM kpi_record 
WHERE kpi_series_id = '15'
AND date_dtm > dateadd(ww,-12,'2013-02-28 00:00:00.000')
group by datepart(ISO_WEEK,date_dtm), datepart(yyyy,date_dtm)
ORDER BY datepart(yyyy,date_dtm), datepart(ISO_WEEK,date_dtm)

--

SELECT datepart(ww,date_dtm) as ww,
datepart(yyyy,date_dtm) as date_year, 
(sum(sum_value)/sum(user_count)) as value 

FROM kpi_record 
WHERE kpi_series_id = '15'
AND date_dtm > dateadd(ww,-12,'2013-02-28 00:00:00.000')
group by datepart(yyyy,date_dtm), datepart(ww,date_dtm)
ORDER BY datepart(yyyy,date_dtm), datepart(ww,date_dtm)

这两个查询的结果分别是:

1   2012    7,14
49  2012    7,31475409836066
50  2012    7,39261285909713
51  2012    7,47905477980666
52  2012    7,30618401206636
1   2013    7,49925705794948
2   2013    7,26598837209302
3   2013    7,24533333333333
4   2013    7,22245989304813
5   2013    6,96774193548387
6   2013    7,24523160762943
7   2013    7,14718019257221
8   2013    7,34691195795007
9   2013    7,23430962343096

49  2012    7,4537037037037
50  2012    7,33109017496635
51  2012    7,4656652360515
52  2012    7,36874051593323
53  2012    7,13888888888889
1   2013    7,50515463917526
2   2013    7,33190271816881
3   2013    7,17693315858453
4   2013    7,24209378407852
5   2013    7,0201072386059
6   2013    7,19281914893617
7   2013    7,17278911564626
8   2013    7,3283378746594
9   2013    7,24733096085409

我的问题,按这个顺序,是:

  • 在第二个查询中(使用常规 ww),本周 53 保存了哪些数据?据我了解,这是进入 2013 年的几天,但仍属于第 52 周,但由于这一年即将结束,因此为那些日子增加了一周。这个对吗?如果没有,请赐教。
  • 在第一个查询 (iso_week) 中,第 1 周是几?我相信这是第二个查询(常规 ww)中看到的第 53 周。但它应该是 2013 年的第一周,或者可能添加到 2013 年的第一周?我很难理解这里发生了什么。
  • 即使解释了这一点,我也不太明白为什么要返回 14 行数据。通过我的查询,我想从我提供的日期开始返回 12 周(例如硬编码)。我怎么可能每周获得 12 行合法数据,而不是 13 或 14 行?如果我使用天而不是星期,它会追溯到 12 天,因此我有 12 行返回给我。

谢谢你的帮助,我希望我是有道理的。

4

2 回答 2

11

ISO标准定义了一年中的第一周(每周是周一到周日),其中 4 天或更多天属于该周(即一周的大部分时间在该年),可以简化为一年的第一周包含一个星期四。

DATEPART(WEEK, 更加简单,它只是DATEFIRST自年初以来经过的周边界数(由 定义)的计数,始终从 1 开始,因此您可以连续三天获得三个不同的周数,如下所示:

SET DATEFIRST 3;
SELECT  [20121231] = DATEPART(WEEK, '20121231'),
        [20130101] = DATEPART(WEEK, '20130101'),
        [20130102] = DATEPART(WEEK, '20130102');

在尝试分析 12 周的数据时获得 14 行的原因有 2 个促成因素,原因适用于 ISO_WEEK 和 WEEK,您的日期范围是 20121206 到 20130228,即使这些日期相隔 12 周,如果您DATEFIRST 与开始日期和结束日期的工作日不匹配,则您的日期范围将跨越 13 周。

ISO_WEEK 函数中的第 14 行是因为没有 ISO_YEAR 函数,在 ISO 标准中,2013 年第 1 周从 2012 年 12 月 31 日开始,但是因为DATEPART(YEAR为此给出了 2012 年,所以它将第 1 周分为 2 行:

Year    Week    DaysInRow
2012    1       1
2013    1       6

使用WEEK时的第14周,由于计算方法简单,同一周(2012年12月31日-2013年1月6日)也分为2周,但如下

Year    Week    DaysInRow
2012    53      1
2013    1       6

如果你有一个日历表,那么你应该有 ISO_YEAR 和 ISO_WEEK 列,所以(如果你不添加它们)你很容易看到 20121231 是 2013 年的第 1 周,如果你没有日历表(我'd 建议您创建一个)您可以创建自己的 UDF:

CREATE FUNCTION dbo.ISO_YEAR @Date DATETIME
RETURNS INT
AS
BEGIN
    DECLARE @ISOyear INT = DATEPART(YEAR, @Date);

    -- Special cases: Jan 1-3 may belong to the previous year
    IF (DATEPART(MONTH, @DATE) = 1 AND DATEPART(ISO_WEEK, @DATE) > 50)
        SET @ISOyear = @ISOyear - 1;

    -- Special case: Dec 29-31 may belong to the next year
    IF (DATEPART(MONTH, @DATE) = 12 AND DATEPART(ISO_WEEK, @DATE) < 45)
        SET @ISOyear = @ISOyear + 1;

    RETURN @ISOYear;
END
于 2013-04-10T08:23:28.517 回答
2

我使用下面更简单的代码来给我一个可靠的 ISO 年份:

DATEPART(YY, @TheDate - (DATEPART(DW, @TheDate) - 4))

……我写了下面的 UDF——包括上面的片段——给我一个可靠的 ISO 年周字符串,我可以用它来报告或按周数排序。

UDF 强制使用两个字符的星期字符串,以避免(例如)2016-9排序 2016-10之后的“陷阱” (我敢打赌,您已经去过那里并这样做了;当然有!):

CREATE FUNCTION [dbo].[ISOYearAndWeek] 
(@TheDate DATETIME) RETURNS NCHAR(7) AS
BEGIN

  DECLARE @Result NCHAR(7)

  SELECT @Result = 
    CONVERT(CHAR(4), DATEPART(YY, @TheDate - (DATEPART(DW, @TheDate) - 4)))
    + '-'
    + CONVERT(CHAR(2), RIGHT('00' + CONVERT(VARCHAR(2), DATEPART(ISOWK, @TheDate)), 2)) 

    RETURN @Result

END
于 2016-03-15T11:43:02.677 回答