Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MSSQL-获取最近6周的回报最近8周_Sql_Sql Server_Dateadd_Datepart - Fatal编程技术网

MSSQL-获取最近6周的回报最近8周

MSSQL-获取最近6周的回报最近8周,sql,sql-server,dateadd,datepart,Sql,Sql Server,Dateadd,Datepart,我对周数有问题。客户周从星期二开始,所以在星期一结束。所以我做了: Set DateFirst 2 当我使用 DateAdd(ww,@WeeksToShow, Date) 它偶尔会给我8周的信息。我想这是因为它已经过去一年了,但我不知道如何修复它 如果我这样做: (DatePart(dy,Date) / 7) - @WeeksToShow 然后它工作得更好,但显然在过去几年里不起作用,因为它只会变成负数 编辑: 如果没有任何数据的话,我的当前SQL是有帮助的 Set DateFirst

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

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

这将使您在本周+5周前从周二开始:

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

tuesday5weeksago  tuesday6weeksago  tuesday7weeksago  tuesdaydynamicweeksago
2015-01-27        2015-01-20        2015-01-13        2015-01-20

这里有两个问题,第一个是我怀疑您将8周的数据定义为DATEPARTWEEK有8个不同的值,在这种情况下,您可以通过查看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
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
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
所以,虽然你只有7天,但你有3个不同的周数。问题是DATEPARTWEEK是一个非常简单的函数,它只返回从一年的第一天起经过的周边界数,更好的函数是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  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
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
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
问题是,这没有考虑到一周从周二开始,因为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
);
或者您可以使用交叉应用:

其中:

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
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
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());

然后,我所做的就是用DATEADDWEEK,-6,GETDATE替换第二个GETDATE,这样它就可以在6周前获得一周的开始,然后只需要一个cast to date来删除其中的时间元素。

您所说的是不可能的。我们需要看完整的SQL语句才能明白这一点,这里没有足够的信息。不确定这会有多大帮助,但添加了!这是一个很好的定义。但是,筛选出零件周不是更容易吗?是的,这是第二部分的内容,通过确保您的开始日期是星期二,您知道不会有零件周。在这种情况下。。这样行吗?选择DatePartyy,Date as Year,Week=DATEPARTISO_Week,DATEADDDAY,-1,Date from TransactionDetail,其中DATEADDWEEK,-6,'2015/01/01'和'2015/01/01'之间的日期按DatePartyy,Date,DATEPARTISO Week,DATEADDDAY,-1,日期顺序按年份,周分组,因此这将GetDate更改为预设值。如果每周都有信息的话,看起来很有效!datepartyy,Date将导致您的问题超出年度边界,因为同一周可能有两个不同的年份,您需要使用我在问题中提出的ISOYear函数。很好。你真是人间的神。非常感谢!