1

我对周数有疑问。客户周从星期二开始,因此在星期一结束。所以我做了:

Set DateFirst 2

当我然后使用

DateAdd(ww,@WeeksToShow, Date)

它偶尔会给我 8 周的信息。我认为这是因为它延续到了前一年,但我不知道如何解决它。

如果我做:

  (DatePart(dy,Date) / 7) - @WeeksToShow

然后它会更好地工作,但显然不会持续到前几年,因为它只会出现负数。

编辑:

我目前的 SQL(如果它在没有任何数据的情况下有帮助的话)

Set DateFirst 2

Select 
    DATEPART(yyyy,SessionDate) as YearNo, 
    DATEPART(ww,SessionDate) as WeekNo,
    DATEADD(DAY, 1 - DATEPART(WEEKDAY, SessionDate + SessionTime),     CAST(SessionDate +SessionTime AS DATE)) [WeekStart],
    DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime),     CAST(SessionDate + SessionTime AS DATE)) [WeekEnd],
    DateName(dw,DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate +     SessionTime), CAST(SessionDate + SessionTime AS DATE))) as WeekEndName,
    Case when @ConsolidateSites = 1 then 0 else SiteNo end as SiteNo,
    Case when @ConsolidateSites = 1 then 'All' else CfgSites.Name end as SiteName,
    GroupNo,
    GroupName,
    DeptNo,
    DeptName,
    SDeptNo,
    SDeptName,
    PluNo,
    PluDescription,
    SUM(Qty) as SalesQty,
    SUM(Value) as SalesValue
From 
    PluSalesExtended
Left Join
    CfgSites on PluSalesExtended.SiteNo = CfgSites.No
Where
    Exists (Select Descendant from DescendantSites where Parent in (@SiteNo) and Descendant = PluSalesExtended.SiteNo)
    AND (DATEPART(WW,SessionDate + SessionTime) !=DATEPART(WW,GETDATE()))
    AND SessionDate + SessionTime between DATEADD(ww,@NumberOfWeeks * -1,@StartingDate) and @StartingDate
    AND TermNo = 0
    AND PluEntryType <> 4
Group by
    DATEPART(yyyy,SessionDate),
    DATEPART(ww,SessionDate),
    DATEADD(DAY, 1 - DATEPART(WEEKDAY, SessionDate + SessionTime),     CAST(SessionDate +SessionTime AS DATE)),
    DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime),     CAST(SessionDate + SessionTime AS DATE)),
    Case when @ConsolidateSites = 1 then 0 else SiteNo end,
    Case when @ConsolidateSites = 1 then 'All' else CfgSites.Name end,
    GroupNo,
    GroupName,
    DeptNo,
    DeptName,
    SDeptNo,
    SDeptName,
    PluNo,
    PluDescription

order by WeekEnd
4

2 回答 2

2

这里有两个问题,第一个是我怀疑您将 8 周的数据定义为具有 8 个不同的值DATEPART(WEEK,在这种情况下,您可以通过查看 ISO 定义的第一周来复制问题的根本原因2015 年:

SET DATEFIRST 2;
SELECT Date, Week = DATEPART(WEEK, Date)
FROM (VALUES 
        ('20141229'), ('20141230'), ('20141231'), ('20150101'),
        ('20150102'), ('20150103'), ('20150104')
    ) d (Date);

这使:

Date        Week
-----------------
2014-12-29  52
2014-12-30  53
2014-12-31  53
2015-01-01  1
2015-01-02  1
2015-01-03  1
2015-01-04  1

因此,尽管您只有 7 天,但您有 3 个不同的周数。问题是这DATEPART(WEEK是一个非常简单的函数,并且只会返回自一年的第一天以来经过的周边界数,更好的函数是ISO_WEEK因为它很好地考虑了年份边界:

SET DATEFIRST 2;
SELECT Date, Week = DATEPART(ISO_WEEK, Date)
FROM (VALUES 
        ('20141229'), ('20141230'), ('20141231'), ('20150101'),
        ('20150102'), ('20150103'), ('20150104')
    ) d (Date);

这使:

Date        Week
-----------------
2014-12-29  1
2014-12-30  1
2014-12-31  1
2015-01-01  1
2015-01-02  1
2015-01-03  1
2015-01-04  1

问题是,这没有考虑到该周从周二开始,因为 ISO 周从周一到周日运行,您可以稍微调整您的用法以获得前一天的周数:

SET DATEFIRST 2;
SELECT Date, Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date))
FROM (VALUES 
        ('20141229'), ('20141230'), ('20141231'), ('20150101'),
        ('20150102'), ('20150103'), ('20150104')
    ) d (Date);

这会给:

Date        Week
-----------------
2014-12-29  52
2014-12-30  1
2014-12-31  1
2015-01-01  1
2015-01-02  1
2015-01-03  1
2015-01-04  1

因此,12 月 29 日星期一现在被认为是前一周。问题是没有ISO_YEAR内置函数,因此您需要定义自己的函数。这是一个相当微不足道的函数,即使我几乎从不创建标量函数,因为它们执行得非常糟糕,而是我使用内联表值函数,所以为此我会使用:

CREATE FUNCTION dbo.ISOYear (@Date DATETIME)
RETURNS TABLE
AS
RETURN
(   SELECT  IsoYear = DATEPART(YEAR, @Date) + 
                        CASE
                            -- Special cases: Jan 1-3 may belong to the previous year 
                            WHEN (DATEPART(MONTH, @Date) = 1 AND DATEPART(ISO_WEEK, @Date) > 50) THEN -1

                            -- Special case: Dec 29-31 may belong to the next year
                            WHEN (DATEPART(MONTH, @Date) = 12 AND DATEPART(ISO_WEEK, @Date) < 45) THEN 1
                            ELSE 0
                        END
);

这只需要使用子查询,但就性能而言,额外的输入是值得的:

SET DATEFIRST 2;
SELECT Date, 
    Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date)),
    Year = (SELECT ISOYear FROM dbo.ISOYear(DATEADD(DAY, -1, Date)))
FROM (VALUES 
        ('20141229'), ('20141230'), ('20141231'), ('20150101'),
        ('20150102'), ('20150103'), ('20150104')
    ) d (Date);

或者您可以使用CROSS APPLY

SET DATEFIRST 2;
SELECT Date, 
    Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date)),
    Year = y.ISOYear
FROM (VALUES 
        ('20141229'), ('20141230'), ('20141231'), ('20150101'),
        ('20150102'), ('20150103'), ('20150104')
    ) d (Date)
    CROSS APPLY dbo.ISOYear(d.Date) y;

这使:

Date        Week    Year
---------------------------
2014-12-29  52      2014
2014-12-30  1       2015
2014-12-31  1       2015
2015-01-01  1       2015
2015-01-02  1       2015
2015-01-03  1       2015
2015-01-04  1       2015

即使使用这种方法,如果您使用的日期不是星期二,只需获取 6 周前的日期,您仍然会得到 7 周,因为您将有 5 个完整的周,以及开始时的部分周和部分一周结束,这是第二期。所以你需要确保你的开始日期是星期二。以下将为您提供 7 周前的星期二:

SELECT CAST(DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), DATEADD(WEEK, -6, GETDATE())) AS DATE);

这个答案的逻辑得到了更好的解释,以下是本周开始的部分(基于您的 datefirst 设置):

SELECT DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), GETDATE());

然后我所做的就是用第二个替换GETDATE()它,DATEADD(WEEK, -6, GETDATE())以便它在 6 周前开始一周,然后只有一个迄今为止的演员表来从中删除时间元素。

于 2015-03-02T09:52:47.477 回答
0

从星期二开始,这将使您获得当前周 + 前 5 周:

WHERE dateadd(week, datediff(d, 0, getdate()-1)/7 - 4, 1) <= yourdatecolumn

这将显示示例:

DECLARE @wks int = 6 -- Weeks To Show

SELECT 
  dateadd(week, datediff(d, 0, getdate()-1)/7 - 4, 1) tuesday5weeksago,
  dateadd(week, datediff(d, 0, getdate()-1)/7 - 5, 1) tuesday6weeksago,
  dateadd(week, datediff(d, 0, getdate()-1)/7 - 6, 1) tuesday7weeksago,
  dateadd(week, datediff(d, 0, getdate()-1)/7 - @wks + 1, 1) tuesdaydynamicweeksago

结果:

tuesday5weeksago  tuesday6weeksago  tuesday7weeksago  tuesdaydynamicweeksago
2015-01-27        2015-01-20        2015-01-13        2015-01-20
于 2015-03-02T09:37:37.873 回答