我有一个表PostingPeriod,它使用公司日历来跟踪所有工作日。简化,它看起来像这样:
a = 1, 2, 3
我有另一张表,其中包含所有带有Orderdate的采购行,供应商确认的交货日期以及orderdate和deliverydate之间工作日的最大允许时间范围:
Date Year Quarter Month Day IsWorkingDay
25.06.2015 2015 2 6 25 1
26.06.2015 2015 2 6 26 1
27.06.2015 2015 2 6 27 0
我想创建一个新列,它返回每个订单的最大允许日期(无论工作日与否)。通常的方法(工作日/ 5周数,乘以7来得到天数)不起作用,因为所有假期等都需要考虑。 由于这是针对将为OLAP数据库提供数据的DWH,因此性能不是问题。
答案 0 :(得分:4)
您可以使用ROW_NUMBER
为每个工作日指定一个任意索引,例如
SELECT Date, WorkingDayIndex = ROW_NUMBER() OVER(ORDER BY Date)
FROM dbo.Calendar
这会给你类似的东西:
Date WorkingDayIndex
-----------------------------
2015-04-27 80
2015-04-28 81
2015-04-29 82
2015-04-30 83
2015-05-01 84
2015-05-05 85
2015-05-06 86
2015-05-07 87
然后,如果您想知道某一日期 n 工作日的日期,请找到索引 n 更高的日期,即2015-04-27指数为80,因此5个工作日后的指数为85,即2015-05-05。
完整的工作示例
/***************************************************************************************************************************/
-- CREATE TABLES AND POPULATE WITH TEST DATA
SET DATEFIRST 1;
DECLARE @Calendar TABLE (Date DATE, IsWorkingDay BIT);
INSERT @Calendar
SELECT TOP 365 DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY object_id), '20141231'), 1 FROM sys.all_objects;
UPDATE @Calendar
SET IsWorkingDay = 0
WHERE DATEPART(WEEKDAY, Date) IN (6, 7)
OR Date IN ('2015-01-01', '2015-04-03', '2015-04-06', '2015-05-04', '2015-05-25', '2015-08-31', '2015-12-25', '2015-12-28');
DECLARE @T TABLE (PurchID INT, OrderDate DATE, ConfDeliveryDate DATE, DeliveryDays INT);
INSERT @T VALUES (1234, '20150414', '20150520', 30), (1235, '20150414', '20150524', 20);
/***************************************************************************************************************************/
-- ACTUAL QUERY
WITH WorkingDayCalendar AS
( SELECT *, WorkingDayIndex = ROW_NUMBER() OVER(ORDER BY Date)
FROM @Calendar
WHERE IsWorkingDay = 1
)
SELECT *
FROM @T AS t
INNER JOIN WorkingDayCalendar AS c1
ON c1.Date = t.OrderDate
INNER JOIN WorkingDayCalendar AS c2
ON c2.WorkingDayIndex = c1.WorkingDayIndex + t.DeliveryDays;
如果这是一个常见的要求,那么您可以在日历表中将WorkingDayIndex
设为固定字段,这样您就不需要在每次需要时计算它。
答案 1 :(得分:2)
从OrderDate开始,如果您提前N(DeliveryDays)WorkingDays,则为日期。
如果我理解正确你想要这样的东西:
select
PurchID,
OrderDate,
ConfDelivery,
DeliveryDay,
myDays.[Date] myWorkingDayDeliveryDate
from Purchases p
outer apply (
select
[Date]
from (
select
ROW_NUMBER() OVER (
ORDER BY
Date
) myDays,
[Date]
from PostingPeriod pp
where
IsWorkingDay = 1 and
pp.date >= p.OrderDate
) myDays
where
myDays = p.DeliveryDay
) myDays
答案 2 :(得分:0)
您必须执行类似
的操作SELECT OrderDate.PurchId, OrderDate.OrderDate, OrderDate.DeliveryDays, Aux.Counter, Aux.Date
FROM OrderDate, (SELECT row_number() OVER (ORDER BY Date) AS Counter, Date FROM PostingPeriod WHERE IsWorkingDay = 1 ) Aux
WHERE Counter = DeliveryDays
ORDER BY 1
基本上,您需要在表PostingPeriod中插入所有日期(周末和假日的IsWorkingDay = 0,其余时间= 1) 这将通过将OrderDate与工作日的数量相加来为您提供最小的日期