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函数。很好。你真是人间的神。非常感谢!