【问题标题】:SQL - Count working days with an exceptionSQL - 计算工作日的例外情况
【发布时间】:2017-10-31 22:39:40
【问题描述】:

我正在使用这个 sql 代码来计算没有周末和节假日的工作日。如果生日日期在 sDate 和 eDate 之间,我该如何减去与生日“B”不同的每个事件类型的生日日期?

SELECT
   evt.[Name],  
   evt.[type],
   evt.sDate,
   evt.eDate,
   DATEDIFF(DD, evt.sDate, evt.eDate) + 1
   - (DATEDIFF(WK, evt.sDate, evt.eDate) * 2) 
   - CASE WHEN DATEPART(DW, evt.sDate) = 1 THEN 1 ELSE 0 END 
   + CASE WHEN DATEPART(DW, evt.eDate) = 1 THEN 1 ELSE 0 END 
   - (SELECT COUNT(*) FROM tblHolidays  AS h WHERE h.Data BETWEEN evt.sDate AND evt.eDate) as date_diff
   -- subtract birthday date if between sDate and eDate
   FROM tblEvents AS evt
   WHERE YEAR(sDate) = YEAR(getdate())
   AND MONTH(sDate) = 12
   ORDER BY evt.[Name]

事件表: 生日列显示是否应从 date_diff 中减去该值

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

【问题讨论】:

  • 标记您正在使用的 dbms。该查询是特定于产品的。
  • 所需输出的格式是什么?
  • 我刚刚替换了表格以添加列“date_diff_final”。所需的列名称是浅蓝色的,但 date_diff (实际)的值应等于 date_diff_final (不包括生日)。我希望我是清楚的!

标签: sql-server


【解决方案1】:

使用left joincase 表达式:

select
   evt.[Name],  
   evt.[type],
   evt.sDate,
   evt.eDate,
   datediff(day, evt.sDate, evt.eDate) + 1
   - (datediff(week, evt.sDate, evt.eDate) * 2) 
   - case when datepart(weekday, evt.sDate) = 1 then 1 else 0 end 
   + case when datepart(weekday, evt.eDate) = 1 then 1 else 0 end 
   - (select count(*) from tblHolidays  as h where h.Data between evt.sDate and evt.eDate) as date_diff
   -- subtract birthday date if between sDate and eDate
   - case when b.sDate is not null then 1 else 0 end
from tblEvents as evt
  left join tblEvents as b
    on evt.Name = b.Name  -- Hopefully there is a better identifier than Name, like an EmpId
   and evt.Type != 'B'
   and b.Type = 'B'
   and b.sDate >= evt.sDate
   and b.sDate <= evt.eDate
where --year(evt.sDate) = year(getdate())
  --and month(evt.sDate) = 12
  /* instead of using functions, use an appropriate date range */
  evt.SDate >= '20171201'
  and evt.SDate < '20180101'
order by evt.[Name]

【讨论】:

  • @ElioFernandes 乐于助人!
【解决方案2】:

使用 CASE 语句代替您的“减去生日”注释,以返回 1 或 0,作为 date_diff 列计算的一部分。

我不清楚您是否有可用的出生日期列,但您要检查的条件不是解决方案的关键,因此请替换您需要在 WHEN 块中检查的任何条件以获取1 或 0 根据您的计算需要。如果您有可用的生日列,它可能看起来像这样:

SELECT CASE 
WHEN evt.Type != 'B' 
AND CAST(CONCAT(month(birthdate), '/', day(birthdate), '/', year(getdate())) AS date) BETWEEN evt.sDate AND evt.eDate 
THEN 1 ELSE 0 END

当嵌入到您的 SELECT 子句中时,它需要使用括号。

仅引用 evt.Type 列,它变得更简单:

SELECT
   evt.[Name],  
   evt.[type],
   evt.sDate,
   evt.eDate,
   DATEDIFF(DD, evt.sDate, evt.eDate) + 1
   - (DATEDIFF(WK, evt.sDate, evt.eDate) * 2) 
   - CASE WHEN DATEPART(DW, evt.sDate) = 1 THEN 1 ELSE 0 END 
   + CASE WHEN DATEPART(DW, evt.eDate) = 1 THEN 1 ELSE 0 END 
   - (SELECT COUNT(*) FROM tblHolidays  AS h WHERE h.Data BETWEEN evt.sDate AND evt.eDate) 
   - CASE WHEN evt.Type != 'B' THEN 1 ELSE 0 END as date_diff
   FROM tblEvents AS evt
   WHERE YEAR(sDate) = YEAR(getdate())
   AND MONTH(sDate) = 12
   ORDER BY evt.[Name]

【讨论】:

  • 如您在代码中看到的,Birthday 列不存在。我只是把它放在那里帮助(对不起,如果它没有帮助)。
  • 如果您没有生日日期,您如何确定生日在 sDate 和 eDate 之间?
  • @JohnMo 我假设type = B的行
  • 为什么不直接减去生日列中的值?这使得数学工作可以到达您问题中的 date_diff_final 列。
  • 约翰,你能重做代码吗,因为没有生日栏。生日是 type = 'B'。
猜你喜欢
  • 2018-02-18
  • 2021-05-09
  • 2021-06-16
  • 2016-02-20
  • 2023-03-19
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
相关资源
最近更新 更多