在sql中模拟Excel网络日

时间:2011-01-22 11:46:41

标签: excel

我确信有人已经尝试用其他编程语言模拟Excel networkdays功能。 如果你可以分享,那就是aprriciate。 谢谢

7 个答案:

答案 0 :(得分:3)

我们的想法是计算每个日期周开始之间的工作日,然后应用各种补偿。

  1. 查找每个日期之前的星期六之间的天数
  2. 除以7并乘以5得到工作日数
  3. 抵消开始日期是否在结束日期之后的总数
  4. 再次抵消开始是在结束之后,开始是星期六
  5. 再次说明开始时间是否结束,结束时间是星期日
  6. 再次判断开始时间是否为星期日
  7. 再次说明开始时间是否结束,结束时间是星期六
  8. 在表格中添加一些随机日期。

    declare @t table ([start] datetime, [end] datetime)
    insert into @t values ('2088-01-14 11:56:23','2011-11-10 03:34:09')
    insert into @t values ('2024-09-24 10:14:29','2087-09-16 15:52:06')
    

    然后为这些日期计算NETWORKDAYS。

        select [start],[end]
        ,((datediff(day,0,[end])-datepart(dw,[end]))-(datediff(day,0,[start])-datepart(dw,[start])))/7*5 --[weekdays]
        + datepart(dw,[end]) - datepart(dw,[start]) --[weekday diff]
        + case when datediff(day,0,[start]) > datediff(day,0,[end]) then -1 else 1 end --[start after]
        + case when datediff(day,0,[start]) > datediff(day,0,[end]) and datepart(dw,[start]) = 7 then 1 else 0 end --[start after and start saturday]
        + case when datediff(day,0,[start]) > datediff(day,0,[end]) and datepart(dw,[end]) = 1 then 1 else 0 end --[start after and end sunday]
        + case when datediff(day,0,[start]) <= datediff(day,0,[end]) and datepart(dw,[start]) = 1 then -1 else 0 end --[start not after and start sunday]
        + case when datediff(day,0,[start]) <= datediff(day,0,[end]) and datepart(dw,[end]) = 7 then -1 else 0 end --[start not after and end saturday]
        as [networkdays]
        from @t
    

答案 1 :(得分:1)

答案 2 :(得分:1)

希望这可以帮助某个人,但这对我有用。需要您创建dbo.FederalHolidays表(可以使用在线日期源轻松填充该表)。 我想出的最简洁的方法很容易扩展。

return !string.IsNullOrEmpty(webBrowser.Document.GetElementById("uiDynamicText").InnerText);

答案 3 :(得分:0)

为了它的价值,我为mysql创建了以下函数,假设周一至周五是工作日:

DROP FUNCTION IF EXISTS BusinessDays;

DELIMITER //

CREATE FUNCTION BusinessDays (startDate DATE, endDate DATE)
RETURNS INT
DETERMINISTIC
BEGIN
  DECLARE startWeekDay INT;
  DECLARE allDays INT;
  DECLARE fullWeekCount INT;
  DECLARE remainderDays INT;
  DECLARE maxPossibleRemainderWeekendDays INT;
  DECLARE soloSundays INT;
  DECLARE totalBusinessDays INT;

  SET startWeekDay = WEEKDAY(startDate);
  SET allDays = ABS(DATEDIFF(endDate, startDate)) + 1;
  SET fullWeekCount = FLOOR(allDays/7);
  SET remainderDays = allDays - (fullWeekCount * 7);
  SET maxPossibleRemainderWeekendDays = ROUND(2*(startWeekDay+remainderDays-6)/(ABS(2*(startWeekDay+remainderDays-6))+1))+1;
  SET soloSundays = ROUND(2*(startWeekDay-6)/(ABS(2*(startWeekDay-6))+1))+1;

  SET totalBusinessDays = allDays - (fullWeekCount * 2) - maxPossibleRemainderWeekendDays + soloSundays;
  RETURN totalBusinessDays;
END //

DELIMITER ;

答案 4 :(得分:0)

也许这也会有所帮助,我创建了一个模拟NETWORKDAYS函数的公式(在Excel中):

= 1 + ( ( B1 - A1) * 5 - ( WEEKDAY(A1) - WEEKDAY(B1) ) * 2 ) / 7 + IF(A1<=B1,IF(WEEKDAY(B1)=7,-1,0) + IF(WEEKDAY(A1)=1,-1,0), IF(WEEKDAY(B1)<>1,-1,0) + IF(WEEKDAY(A1)<>7,-1,0) )

注意:WEEKDAY()星期日为0星期六为6

答案 5 :(得分:0)

我一直在寻找这种功能,所以继续并自行创建了它。

用法:这是您可以在SQL中创建的函数。您可以轻松地对此进行修改,以在需要时在函数外部工作,但是我更喜欢函数来处理这些类型的计算。

我添加了很多评论,以防有人怀疑它是如何工作的。这需要两个输入:

  • @startDate-您要添加工作日的开始日期。
  • @addDays-您要添加到@startDate的总天数。

计算过程: 重复循环直到达到工作天数。例如,如果输入365天,它将循环大约500次,然后才能预测要添加的工作日数。我添加了@weekendCount,以防有人在到达最终结束日期之前需要知道排除的周末数。

完成后,整数@recCounter本质上是达到工作天数之前必须添加到@startDate的天数。我确信有人可以比我写得更好,或者有人可以利用它。希望这可以帮助! :)

CREATE FUNCTION  [dbo].[addNetworkDays](@startDate AS DATETIME, @addDays AS Int)
RETURNS DATETIME
AS
BEGIN
    DECLARE @recCounter Int
        SET @recCounter = 0
    DECLARE @weekendCount Int
        SET @weekendCount = 0
    DECLARE @workdayCount Int
        SET @workdayCount = 0
    DECLARE @newDate DateTime

    WHILE @addDays > @workdayCount

    BEGIN
        -- Add another day to the start date
        SET @recCounter = @recCounter + 1
        -- Cumuluate the weekend vs. workday counter, based on the day of the week. This loop will repeat until @workdayCount has reached the @addDays.
        -- Note that @weekendCount is not used in any capacity, can be used if you need to know how many weekend days there are.
        IF DATEPART(dw, DATEADD(d, @recCounter, @startDate)) IN (1, 7) SET @weekendCount = @weekendCount + 1
        IF DATEPART(dw, DATEADD(d, @recCounter, @startDate)) IN (2, 3, 4, 5, 6) SET @workdayCount = @workdayCount + 1
    END

        -- At this point, the script has completed the cycle, stopping when the detected # of workdays has reached the count of days the user specified.
        -- Calculate the new date, based on the # of cycles *days* detected above.
        SET @newDate = DATEADD(d, @recCounter, @startDate)
        -- If the new/adjusted date falls on a Saturday or Sunday, add additional days to compensate.
        IF DATEPART(dw, @newDate) = 1 SET @newDate = DATEADD(d, 1, @newDate)
        IF DATEPART(dw, @newDate) = 7 SET @newDate = DATEADD(d, 1, @newDate)
    RETURN CAST(@newDate AS DATETIME)

答案 6 :(得分:0)

澳大利亚的NETWORKDAYS

WITH PH_NET_WORKDAY AS
(
----BUILD UNDERLYING WORKDAY DATA TABLE
SELECT
    DT,
    STATE,
    CASE 
        WHEN WORKDAY-PUBLIC_HOLIDAY <0
        THEN 0
        ELSE WORKDAY-PUBLIC_HOLIDAY
    END AS WORKDAY
FROM
    (
    SELECT 
        DT,
        STATE,
        WORKDAY,
        ----PUBLIC HOLIDAY INFORMATION HERE
        CASE
            WHEN STATE = 'NSW'
            THEN
                CASE 
                    WHEN DT IN (
                                '01-Oct-2018',
                                '25-Dec-2018',
                                '26-Dec-2018',
                                '01-Jan-2019',
                                '28-Jan-2019',
                                '19-Apr-2019',
                                '20-Apr-2019',
                                '21-Apr-2019',
                                '22-Apr-2019',
                                '25-Apr-2019',
                                '10-Jun-2019',
                                '07-Oct-2019',
                                '25-Dec-2019',
                                '26-Dec-2019'
                                )
                    THEN 1
                    ELSE 0
                END
            WHEN STATE = 'SA'
            THEN
                CASE 
                    WHEN DT IN (
                                '01-Oct-2018',
                                '24-Dec-2018',
                                '25-Dec-2018',
                                '26-Dec-2018',
                                '31-Dec-2018',
                                '01-Jan-2019',
                                '28-Jan-2019',
                                '11-Mar-2019',
                                '19-Apr-2019',
                                '20-Apr-2019',
                                '22-Apr-2019',
                                '25-Apr-2019',
                                '10-Jun-2019',
                                '07-Oct-2019',
                                '24-Dec-2019',
                                '25-Dec-2019',
                                '26-Dec-2019'
                                )
                    THEN 1
                    ELSE 0
                END
            WHEN STATE = 'QLD'
            THEN
                CASE 
                    WHEN DT IN (
                                '01-Oct-2018',
                                '25-Dec-2018',
                                '26-Dec-2018',
                                '01-Jan-2019',
                                '28-Jan-2019',
                                '19-Apr-2019',
                                '20-Apr-2019',
                                '21-Apr-2019',
                                '22-Apr-2019',
                                '25-Apr-2019',
                                '06-May-2019',
                                '07-Oct-2019',
                                '25-Dec-2019',
                                '26-Dec-2019'
                                )
                    THEN 1
                    ELSE 0
                END
            WHEN STATE = 'VIC'
            THEN
                CASE 
                    WHEN DT IN (
                                '28-Sep-2018',
                                '06-Nov-2018',
                                '25-Dec-2018',
                                '26-Dec-2018',
                                '01-Jan-2019',
                                '28-Jan-2019',
                                '11-Mar-2019',
                                '19-Apr-2019',
                                '20-Apr-2019',
                                '21-Apr-2019',
                                '22-Apr-2019',
                                '25-Apr-2019',
                                '10-Jun-2019',
                                '05-Nov-2019',
                                '25-Dec-2019',
                                '26-Dec-2019'
                                )
                    THEN 1
                    ELSE 0
                END
            WHEN STATE = 'TAS'
            THEN
                CASE 
                    WHEN DT IN (
                                '25-Dec-2018',
                                '26-Dec-2018',
                                '01-Jan-2019',
                                '28-Jan-2019',
                                '11-Mar-2019',
                                '19-Apr-2019',
                                '22-Apr-2019',
                                '23-Apr-2019',
                                '25-Apr-2019',
                                '10-Jun-2019',
                                '25-Dec-2019',
                                '26-Dec-2019'
                                )
                    THEN 1
                    ELSE 0
                END
            ELSE 0
        END AS PUBLIC_HOLIDAY
    FROM
        (
        SELECT
            DT.*,
            ST.*
        FROM
            (
            SELECT 
                TRUNC (TO_DATE('01-JAN-2021','DD-MON-YYYY') - ROWNUM) AS DT,
                TRIM(TO_CHAR( TRUNC (TO_DATE('01-JAN-2021','DD-MON-YYYY') - ROWNUM) , 'DAY')) AS WEEK_DAY,
                CASE
                    WHEN TRIM(TO_CHAR( TRUNC (TO_DATE('01-JAN-2021','DD-MON-YYYY') - ROWNUM) , 'DAY')) = 'SATURDAY'
                    THEN 0
                    WHEN TRIM(TO_CHAR( TRUNC (TO_DATE('01-JAN-2021','DD-MON-YYYY') - ROWNUM) , 'DAY')) = 'SUNDAY'
                    THEN 0
                    ----BUILD STATE PUBLIC HOLIDAY DATE SET HERE, WE CAN EXCLUDE PUBLIC HOLIDAYS
                    ELSE 1
                END AS WORKDAY
            FROM DUAL CONNECT BY ROWNUM < (365.25*8+1)
            ) DT
            ,
            (
            SELECT 'NSW' AS STATE FROM DUAL
            UNION
            SELECT 'QLD' AS STATE FROM DUAL
            UNION
            SELECT 'SA' AS STATE FROM DUAL
            UNION
            SELECT 'ACT' AS STATE FROM DUAL
            UNION
            SELECT 'VIC' AS STATE FROM DUAL
            UNION
            SELECT 'ACT' AS STATE FROM DUAL
            ) ST
        )
    )
),

----A SAMPLE DATA SET FOR SAME DATES BETWEEN DIFFERENT STATE TO TEST PUBLIC HOLIDAY DIFFERENCES
SAMPLE_DATA AS
(
SELECT 
    '01-FEB-2019' AS D1,
    '11-FEB-2019' AS D2,
    'NSW' AS STATE
FROM DUAL
UNION
SELECT 
    '01-FEB-2019' AS D1,
    '11-FEB-2019' AS D2,
    'SA' AS STATE
FROM DUAL
UNION
SELECT 
    '19-APR-2019' AS D1,
    '26-APR-2019' AS D2,
    'NSW' AS STATE
FROM DUAL
)

----SELECT WORKDAYS FROM PH TABLE AND INSERT INTO SAPLE TABLE
SELECT
SAMPLE_DATA.*,
(
SELECT SUM(WORKDAY)
FROM PH_NET_WORKDAY
WHERE 
    STATE = SAMPLE_DATA.STATE
    AND DT>=SAMPLE_DATA.D1
    AND DT<=SAMPLE_DATA.D2
)
AS WORKDAYS
FROM SAMPLE_DATA