【问题标题】:sum count day each year (SQL)每年计算天数 (SQL)
【发布时间】:2017-06-24 11:53:51
【问题描述】:

我的例子:

 Code            FromDate          ToDate                 
 --              --------           -------        
 101               15/12/2012         15/01/2013   
 101               30/11/2013         20/01/2014 

我想计算两个日期之间的差异,今年有多少天 , 我怎么能用 SQL 做到这一点? 是这样的结果:

 Code    No.day     2012   2013  2014
 --      ------     ----   ----  ----
 101       82        17     46    19

【问题讨论】:

  • 查看SUM()。 (可能与GROUP BY结合使用。)
  • 我没有专栏 No.day ,2012,2013&2014
  • 计数号。 day,2012 你对计数是什么意思。根据您迄今为止的数据,给出 2012 年有 17 个等的逻辑?
  • 是的,从日期到年末...从明年开始到 2013 年 1 月 15 日

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


【解决方案1】:

尝试类似:

select Code,sum([2012])+sum([2013])+sum([2014]) as 'No.days',sum([2012]),sum([2013]),sum([2014]) from(
select Code,
    case when datepart(yy,fromdate)=datepart(yy,todate) and datepart(yy,fromdate)=2012 then  datediff(dd,fromdate, todate)
    when datepart(yy,fromdate)=2012 and  datepart(yy,todate)>2012 then datediff(dd,fromdate,dateadd(yy,1,dateadd(dd,-datepart(dy,DATEADD(yy,1, fromdate)),fromdate)))
    when datepart(yy,fromdate)<2012 and  datepart(yy,todate)=2012 then  DATEPART(dy,todate)
    end as '2012',
    case when datepart(yy,fromdate)=datepart(yy,todate) and datepart(yy,fromdate)=2013 then  datediff(dd,fromdate, todate)
    when datepart(yy,fromdate)=2013 and  datepart(yy,todate)>2013 then  datediff(dd,fromdate,dateadd(yy,1,dateadd(dd,-datepart(dy,DATEADD(yy,1, fromdate)),fromdate)))
    when datepart(yy,fromdate)<2013 and  datepart(yy,todate)=2013 then  DATEPART(dy,todate)
    end as '2013',
    case when datepart(yy,fromdate)=datepart(yy,todate) and datepart(yy,fromdate)=2014 then  datediff(dd,fromdate, todate)
    when datepart(yy,fromdate)=2014 and  datepart(yy,todate)>2014  then  datediff(dd,fromdate,dateadd(yy,1,dateadd(dd,-datepart(dy,DATEADD(yy,1, fromdate)),fromdate)))
    when datepart(yy,fromdate)<2014 and  datepart(yy,todate)=2014 then  DATEPART(dy,todate)
    end as '2014'
    from myTable
    ) as daystable
group by Code

如果您需要更多年,则需要在子查询中添加更多字段。

【讨论】:

  • 小心:您可能需要转义2012,以免RDBMS 将其误认为是数字。
【解决方案2】:

您需要结合几种不同的技术,才能获得您想要的结果。

如果您有calendar table,它会有所帮助。这些都是非常有用的东西,如果您不熟悉,非常值得研究。我的查询假设您没有。在这里,我使用recursive CTE 即时创建了一个。

样本数据

提示:以我们可以共享的格式提供示例数据,可以提高您的问题得到答案的几率。

-- Table variables are a good way to share sample data.
DECLARE @Sample TABLE
    (
        Code        INT,
        FromDate    DATE,
        ToDate      DATE
    )
;

INSERT INTO @Sample
    (
        Code,
        FromDate,
        ToDate
    )
VALUES
    (101, '2012-12-15', '2013-01-15'),
    (101, '2013-11-30', '2014-01-20')
;

查询

此查询将您的源数据连接到日历表。在开始日期和结束日期之间的每一天返回一条记录。使用日历表中的年份列,我们对结果进行分组。计算记录会返回经过的总天数。要计算年份小计,我们使用conditional aggregation。此技术使用case expression 创建新列,根据年份有条件地填充 1 或 0。

/* Returns date counts, split by
 * year.
 */
WITH CalendarTable AS
    (
        /* This CTE returns 1 record for each day 
         * between Jan 1st 2012 and Dec 31st 2014.
         */
            SELECT
                CAST('2012-01-01' AS DATE)  AS [Date],
                2012                        AS [Year]

        UNION ALL

            SELECT
                DATEADD(DAY, 1, [Date])         AS [Date],
                YEAR(DATEADD(DAY, 1, [Date]))   AS [Year]
            FROM
                CalendarTable 
            WHERE
                [Date] < '2014-12-31'
    ) 
SELECT
    s.Code,
    COUNT(*)                                            AS [No.Day],
    SUM(CASE WHEN ct.[Year] = 2012 THEN 1 ELSE 0 END)   AS [2012],
    SUM(CASE WHEN ct.[Year] = 2013 THEN 1 ELSE 0 END)   AS [2013],
    SUM(CASE WHEN ct.[Year] = 2014 THEN 1 ELSE 0 END)   AS [2014]
FROM
    @Sample AS s
        INNER JOIN CalendarTable AS ct      ON  ct.[Date] >= s.FromDate 
                                            AND ct.[Date] < s.ToDate    
GROUP BY
    s.Code
OPTION 
    (MAXRECURSION 1096) 
;

返回

Code    No.day     2012   2013  2014
--      ------     ----   ----  ----
101       82        17     46    19

如果您已经有一个日历表,则可以通过删除 CTE 并更新联接来简化此查询。

【讨论】:

    【解决方案3】:

    使用这个:

       SELECT Code,SUM(No.day) AS No.day, SUM(2012) AS 2012, SUM(2013) AS 2013, SUM(2014) AS 2014
        FROM TABLENAME GROUP BY Code
    

    根据您当前(已编辑)的问题,您应该使用

    SELECT DATEDIFF(day,'2012-06-05','2012-08-05') AS Year2012 From TABLENAME.

    例如:

    SELECT DATEDIFF(day, '2014/01/01', '2014/04/28');
    Result: 117
    
    SELECT DATEDIFF(hour, '2014/04/28 08:00', '2014/04/28 10:45');
    Result: 2
    
    SELECT DATEDIFF(minute, '2014/04/28 08:00', '2014/04/28 10:45');
    Result: 165
    

    您可以根据自己的要求对其进行操作。

    【讨论】:

    • 小心:您可能需要转义 2012,以免 RDBMS 将其误认为是数字。
    【解决方案4】:
    SELECT     code,fromdate,todate,datediff(dd,fromdate,todate),
                    datediff(dd,case when year(fromdate) < 2012 then '1/1/2012' when year(fromdate) = 2012 then fromdate else '12/31/2012' end,case when year(todate) = 2012 then todate else '12/31/2012'end)'2012',
                    datediff(dd,case when year(fromdate) < 2013 then '1/1/2013' when year(fromdate) = 2013 then fromdate else '12/31/2013' end,case when year(todate) = 2013 then todate else '12/31/2013'end)  '2013',
                    datediff(dd,case when year(fromdate) < 2014 then '1/1/2014' when year(fromdate) = 2014 then fromdate else '12/31/2014' end,case when year(todate) < 2014 then '1/1/2014' when year(todate) = 2014 then todate else '12/31/2014'end)  '2014' FROM (SELECT     '101' AS code, datefromparts(2012,12,15) AS fromdate, datefromparts(2013,1,15) AS todate
              UNION
              SELECT     '101' AS code, datefromparts(2013,11,30) AS fromdate, datefromparts(2014,1,20) AS todate
              Union 
              SELECT     '101' AS code, datefromparts(2014,11,30) AS fromdate, datefromparts(2016,1,20) AS todate) AS s
    

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      相关资源
      最近更新 更多