【问题标题】:How to get the summation of days in specific month of year in range如何获取范围内特定月份的天数总和
【发布时间】:2015-09-16 11:29:58
【问题描述】:

如果我有以下结构的假期表:

emp_num start_date   end_date
 234     8-2-2015    8-5-2015
 234     6-28-2015   7-1-2015
 234     8-29-2015   9-2-2015
 115     6-7-2015    6-7-2015
 115     8-7-2015    8-10-2015

考虑日期格式为:m/dd/yyyy

我怎样才能得到每个员工在特定月份的假期总和。

说我想在8Aug-2015度假

我想要这样的结果

emp_num   sum
234        7
115        4

7 = 8-2-2015 and 8-5-2015 plus 之间的所有日子8-29-2015 AND 8-31-2015 月底之间的所有日子

【问题讨论】:

  • 如何达到预期的效果?你能详细说明一下吗?
  • 您使用的是 Informix 还是 SQL Server?请适当标记您的问题。
  • 你过得怎么样?
  • @FelixPamittan:我编辑我的问题
  • 检查来自@FelixPamittan stackoverflow.com/a/32470363/2635532 的答案。好的起点。您需要应用类似的概念。您需要获取月结束日期,而不是季度结束日期。

标签: sql sql-server date informix


【解决方案1】:

希望对你有帮助

declare @temp table
(emp_num int, startdate date, enddate date)


 insert into @temp values (234,'8-2-2015','8-5-2015')
 insert into @temp values (234,'6-28-2015','7-1-2015')
 insert into @temp values (234,'8-29-2015','9-2-2015')
 insert into @temp values (115,'6-7-2015','6-7-2015')
 insert into @temp values (115,'8-7-2015','8-10-2015')
-- i am passing 8 as month number in your case is August
 select emp_num,
 SUM(
 DATEDIFF (DAY , startdate,  
 case when MONTH(enddate) = 8
            then enddate
            else DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,startdate)+1,0))--end date of month
            end
 )+1) AS Vacation from @temp
 where (month(startdate) = 8 OR month(enddate) = 8) AND (Year(enddate)=2015 AND Year(enddate)=2015)
 group by emp_num

更新在有效评论后:这将在以下日期失败:2015-07-01、2015-09-30 –@t-clausen.dk
我假设 OP 只想要一个月,他会通过

declare @temp table
(emp_num int, startdate date, enddate date)


 insert into @temp values (234,'8-2-2015','8-5-2015')
 insert into @temp values (234,'6-28-2015','7-1-2015')
 insert into @temp values (234,'8-29-2015','9-2-2015')
 insert into @temp values (115,'6-7-2015','6-7-2015')
 insert into @temp values (115,'8-7-2015','8-10-2015')

 insert into @temp values (116,'07-01-2015','9-30-2015')


 select emp_num,
 SUM(
 DATEDIFF (DAY , startdate,  
 case when MONTH(enddate) = 8 
            then enddate
            else DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,startdate)+1,0))
            end
 )+1) AS Vacation from @temp
 where (Year(enddate)=2015 AND Year(enddate)=2015) 
 AND 8 between MONTH(startdate) AND MONTH(enddate)
 group by emp_num

【讨论】:

  • 哇。与此相比,我的解决方案太复杂了,但我认为这是正确的。 +1
  • @tinka :谢谢,但这会产生错误的数据,因为它没有考虑年份
  • 这将在以下日期失败:2015-07-01、2015-09-30
  • @t-clausen.dk 编辑我的答案后,它正在填充正确的答案,如果你解释一下或编辑答案,我非常感谢:)
  • 当假期日期是 2015-12-31 和 2016-01-01 并且您正在检查第 12 个月时,这在月份检查和年份检查中也会失败
【解决方案2】:

这适用于 sqlserver 2012+

DECLARE @t table
(emp_num int, start_date date, end_date date)
INSERT @t values
( 234, '8-2-2015' , '8-5-2015'),
( 234, '6-28-2015', '7-1-2015'),
( 234, '8-29-2015', '9-2-2015'),
( 115, '6-7-2015' , '6-7-2015'),
( 115, '8-7-2015' , '8-10-2015')


DECLARE @date date = '2015-08-01'

SELECT
   emp_num,
   SUM(DATEDIFF(day, 
                CASE WHEN @date > start_date THEN @date ELSE start_date END,
                CASE WHEN EOMONTH(@date) < end_date 
                     THEN EOMONTH(@date)
                     ELSE end_date END)+1) [sum]
FROM @t
WHERE 
  start_date <= EOMONTH(@date)
  and end_date >= @date
GROUP BY emp_num

【讨论】:

    【解决方案3】:

    使用Tally Table

    SQL Fiddle

    DECLARE @month INT,
            @year  INT
    
    SELECT @month = 8, @year = 2015
    
    --SELECT
    --  DATEADD(MONTH, @month - 1, DATEADD(YEAR, @year - 1900, 0)) AS start_day, 
    --  DATEADD(MONTH, @month, DATEADD(YEAR, @year - 1900, 0)) AS end_d
    
    ;WITH CteVacation AS(
        SELECT 
            emp_num, 
            start_date = CONVERT(DATE, start_date, 101),
            end_date = CONVERT(DATE, end_date, 101) 
        FROM vacation
    )
    ,E1(N) AS(
        SELECT * FROM(VALUES
            (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
        )t(N)
    ),
    E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b),
    E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b),
    Tally(N) AS(
        SELECT TOP(SELECT MAX(DATEDIFF(DAY, start_date, end_date)) FROM vacation)
            ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
        FROM E4
    )
    SELECT
        v.emp_num,
        COUNT(*)
    FROM CteVacation v
    CROSS JOIN Tally t
    WHERE
        DATEADD(DAY, t.N - 1, v.start_date) <= v.end_date
        AND DATEADD(DAY, t.N - 1, v.start_date) >= DATEADD(MONTH, @month - 1, DATEADD(YEAR, @year - 1900, 0))
        AND DATEADD(DAY, t.N - 1, v.start_date) < DATEADD(MONTH, @month, DATEADD(YEAR, @year - 1900, 0))
    GROUP BY v.emp_num
    

    首先,您想使用正确的数据类型来简化计算。在我的解决方案中,我使用 CTE 来格式化您的数据类型。然后建立一个从 1 到所有假期的最长持续时间的统计表。使用该计数表,在vacation 表上执行CROSS JOIN,以生成从其start_dateend_date 的所有假期日期。

    之后,添加一个WHERE 子句来过滤落在传递的month-year 参数上的日期。

    这里,@month@year 被声明为 INT。你想要的是从month-year 的第一天到最后一天的所有日期。 month 的第一天计算公式为:

    DATEADD(MONTH, @month - 1, DATEADD(YEAR, @year - 1900, 0)) 
    

    对于month 的最后一天,在上面加上一个月,然后使用&lt;

    DATEADD(MONTH, @month, DATEADD(YEAR, @year - 1900, 0))
    

    【讨论】:

    • 非常感谢,我会试试看,你能解释一下Then build a tally table from 1 up to the max duration of the all the vacations.是什么意思
    • 阅读问题中引用的文章。
    • 非常感谢 +1 的精彩解释,只是它比 @t-clausen.dk 回答慢
    【解决方案4】:
    Select(emp_name,start_date,end_date) AS sum_day from table_Name Group by emp_num,start_date,end_date
    

    【讨论】:

      【解决方案5】:

      试试这个

        with cte(
        Select emp_num,DATEDIFF(day,start_date,end_date) AS sum_day from table_Name
        Group by emp_num,start_date,end_date
        )
        Select emp_num,sum(sum_day) as sum_day from cte group by emp_num
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多