简体   繁体   English

正确计算 SQL 中的工作日

[英]Calculate correctly the working days in SQL

I have this a table with some user id events ( starting table ).我有一个包含一些用户 ID 事件的表(起始表)。

In this table there is a Event_Id = 1 that refers to a Local Holiday (it's not a working day).在此表中有一个 Event_Id = 1 表示当地假期(不是工作日)。

在此处输入图像描述

I need to fill the column 'Event_1' to be able to calculate correctly the WorkingDays ( result table - below ).我需要填写“Event_1”列才能正确计算WorkingDays(结果表 - 如下)。

  • In each row where the Event_Id <> 1, the Event_1 column should have a 1 if the corresponding user as matching Event_Id = 1 between the StartDate and EndDate, else it should be 0.在 Event_Id <> 1 的每一行中,如果对应的用户在 StartDate 和 EndDate 之间匹配 Event_Id = 1,则 Event_1 列应为 1,否则应为 0。

  • If the row in analysis as Event_id = 1 the value in Event_1 column如果分析中的行为 Event_id = 1,则 Event_1 列中的值
    should be 0 as well.也应该为 0。

I already have a function that calculates the WorkingDays.我已经有一个计算工作日的 function。

在此处输入图像描述

Regards, Elio Fernandes问候, 埃利奥·费尔南德斯

I came up with this solution, but I would like to know if you think it's the best way to do it.我想出了这个解决方案,但我想知道您是否认为这是最好的方法。

Select T1.*,
    Case
        When t2.StartDate Is not Null and t1.Event_Id = 1 then 0
        When t2.StartDate Is not Null Then 1 
        Else 0
    End As [Local_Holiday]
From 
    [plann].[Events]  as T1 left Join
    (Select StartDate
        From [plann].[Events] 
        Where Event_Id = 1 ) as T2 ON T2.StartDate Between T1.StartDate and T1.EndDate

No. You can move the filter to the on clause and get rid of the subquery:不,您可以将过滤器移动到on子句并摆脱子查询:

Select e1.*,
       (Case When e2.StartDate Is not Null and e1.Event_Id = 1 then 0
             When e2.StartDate Is not Null Then 1 
             Else 0
        End) As [Local_Holiday]
From [plann].[Events] e left Join
     [plann].[Events] e2
     on e2.Event_Id = 1 and
        e2.StartDate Between e1.StartDate and e1.EndDate;

Comparing the data results between your blue table and green table, it appears that the value of Event_1 is the number of days assigned to the “Local Holiday.”比较蓝表和绿表的数据结果,Event_1 的值似乎是分配给“当地假日”的天数。

If a “Local Holiday” will only EVER equal one day and all “Local Holiday” records apply to any user whose vacation coincides with the holiday, then Gordon's solution works (and I like how he gets rid of the subquery).如果“本地假期”仅等于一天,并且所有“本地假期”记录适用于假期与假期重合的任何用户,那么 Gordon 的解决方案有效(我喜欢他摆脱子查询的方式)。

However, you may need to address other considerations.但是,您可能需要解决其他注意事项。

Per your data results, each user with a Local Holiday that occurs during their vacation has a separate record indicating this, which means that the existence of a holiday record per user matters.根据您的数据结果,在假期期间发生本地假期的每个用户都有单独的记录表明这一点,这意味着每个用户是否存在假期记录很重要。 If so, include an additional join for [User Ud].如果是这样,请为 [User Ud] 添加一个附加联接。

LEFT JOIN plann.Events e2 ON e2.Event_Id = 1 
    AND e2.StartDate BETWEEN e1.StartDate AND e1.EndDate 
    AND e2.[User Ud] = e1.[User Ud]

WITHOUT the [User Ud] join, if user 22 has a holiday within his vacation time, then the holiday is recognized—but his data result is inconsistent compared to the others because he does not have a record assigned to him with an Event_Id = 1.如果没有 [User Ud] 加入,如果用户 22 在其休假时间内有假期,则可以识别该假期 - 但与其他人相比,他的数据结果不一致,因为他没有分配给他的 Event_Id = 1 的记录.

WITH the [User Ud] join, you get consistent results, but this leads to design issues and limitations.通过 [User Ud] 加入,您可以获得一致的结果,但这会导致设计问题和限制。

Suppose a “Local Holiday” pertains to all users (typical).假设“本地假期”适用于所有用户(典型)。 If so, I suggest creating a separate holiday table.如果是这样,我建议创建一个单独的假期表。 Accessing the table for applicable dates ensures that all holidays are recognized for all users with an applicable vacation date range.访问适用日期的表格可确保为具有适用假期日期范围的所有用户识别所有假期。

I modified the script removing the assumption that a holiday is always one day (Canada, the UK, and other countries have two public holidays in a row).我修改了脚本,去掉了假期总是一天的假设(加拿大、英国和其他国家连续两个公共假期)。 This consideration led me back to using a subquery.这种考虑使我重新使用子查询。

SELECT
    e1.[User Ud],
    e1.Event_Id,
    e1.Event,
    e1.StartDate,
    e1.EndDate,
    CASE
        WHEN e1.Event_Id = 1
        THEN 0
        WHEN e2.[User Ud] IS NOT NULL
        THEN Number_Days
        ELSE 0
    END AS Holiday_Nmbr_Days,
    WorkingDays

FROM plann.Events e1

LEFT JOIN
    (SELECT
        [User Ud],
        DATEDIFF(dd,StartDate,EndDate) + 1 AS Number_Days,
        StartDate
    FROM plann.Events
    WHERE Event_Id = 1) AS e2 ON e2.Startdate BETWEEN e1.Startdate AND e1.EndDate
        AND e2.[User Ud] = e1.[User Ud] /*Exclude if not applicable*/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM