将X个工作日添加到日期

时间:2015-06-25 13:45:21

标签: sql sql-server sql-server-2008 tsql

我有一个表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,因此性能不是问题。

3 个答案:

答案 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与工作日的数量相加来为您提供最小的日期