如何在MySQL中以年,月和日为单位的持续时间总和?

时间:2017-10-18 17:55:54

标签: mysql datetime

我有一个表格持续时间:

-------------------------------
| id |    from    |     to    |
|----|------------|-----------|
|  1 | 2011-02-22 |    NULL   |
|  2 | 1999-08-03 |2005-03-30 |
|  3 | 1982-09-03 |1988-01-30 |
|  4 | 1965-12-01 |1980-05-02 |
-------------------------------

我想计算一行中的时差(来自)并将它们加起来。我的疑问是:

SELECT CONCAT(SUM(TIMESTAMPDIFF( YEAR, from, IF(to IS NULL,'2017-10-
18', to))),' Years ',
SUM(TIMESTAMPDIFF( MONTH, from, IF(to IS NULL,'2017-10-18', to)) 
% 12),' Months ',
SUM(FLOOR( TIMESTAMPDIFF( DAY, from, IF(to IS NULL,'2017-10-18', 
to)) % 30.4375 )),' Days ') AS Duration
FROM duration;

我得到了:

------------------------------
|         Duration           |
|----------------------------|
| 30 Years 23 Months 78 Days |
------------------------------

但我想得到:

-----------------------------
|         Duration          |
|---------------------------|
| 32 Years 1 Months 18 Days |
-----------------------------

请帮忙!

4 个答案:

答案 0 :(得分:1)

我试图在下面提供一系列查询,以显示确定持续时间/月/日的准确方法(尽管这些计算结果 32年1个月22天可能是因为"现在" )的变化而且我还没有添加最终的连接,这是很难实现的。所使用的方法每行准确,但确实依赖在最终计算月份和日期的每月近似天数(30.4375 *)。

  1. TIMESTAMPDIFF(YEAR , from_dt, to_dt )给出每行的年数
  2. TIMESTAMPDIFF(MONTH, from_dt + INTERVAL TIMESTAMPDIFF(YEAR , from_dt, to_dt) YEAR , to_dt )将年数添加到开始日期,然后获取该日期与结束日期之间的差异
  3. TIMESTAMPDIFF(DAY , from_dt + INTERVAL TIMESTAMPDIFF(MONTH, from_dt, to_dt) MONTH , to_dt )现在将总月数添加到开始日期,然后计算剩余的ays到达结束日期
  4. 请注意,如果给定开始日期+年+月+天(参见查询4),则可以准确地重新计算结束日期。
  5. nb:我使用了多个"层"在下面的查询中,它们更容易阅读(我希望)。

    SQL Fiddle

    MySQL 5.6架构设置

    CREATE TABLE duration
      ( 
         from_dt DATE,  to_dt DATE 
      ); 
    
    INSERT INTO duration 
    VALUES  ('2011-02-22', NULL )
          , ('1999-08-03', '2005-03-30' )
          , ('1982-09-03', '1988-01-30' )
          , ('1965-12-01', '1980-05-02' )
    ; 
    

    查询1

    ## adjusted sums( method using timestampdiff ) 
    SELECT
          CASE WHEN SUM(d.months) > 12 THEN SUM(d.years) + FLOOR(SUM(d.years/12)) ELSE SUM(d.years) END
          as years
        , CASE WHEN SUM(d.days) > 30 THEN FLOOR(((SUM(d.months) + FLOOR(SUM(d.days/30.4375)))/12)) ELSE SUM(d.months) END
          as months
        , CASE WHEN SUM(d.days) > 30 THEN FLOOR(MOD(SUM(d.days), 30)) ELSE SUM(d.months) END
          as days
        , current_date
    FROM (
          SELECT
                  TIMESTAMPDIFF(YEAR , from_dt, to_dt )
                  as years
                , TIMESTAMPDIFF(MONTH, from_dt + INTERVAL TIMESTAMPDIFF(YEAR , from_dt, to_dt) YEAR  , to_dt )
                  as months
                , TIMESTAMPDIFF(DAY  , from_dt + INTERVAL TIMESTAMPDIFF(MONTH, from_dt, to_dt) MONTH , to_dt )
                  as days
          FROM (
                SELECT
                     from_dt
                    , COALESCE(to_dt,CURRENT_DATE) to_dt
                FROM duration
              ) d2
        ) d
    

    <强> Results

    | years | months | days | current_date |
    |-------|--------|------|--------------|
    |    32 |      2 |   22 |   2017-10-19 |
    

    查询2

    ## simple sums( method using timestampdiff )
    SELECT
            sum(TIMESTAMPDIFF(YEAR , from_dt, to_dt ))
            years
          , sum(TIMESTAMPDIFF(MONTH, from_dt + INTERVAL TIMESTAMPDIFF(YEAR , from_dt, to_dt) YEAR  , to_dt ))
            months
          , sum(TIMESTAMPDIFF(DAY  , from_dt + INTERVAL TIMESTAMPDIFF(MONTH, from_dt, to_dt) MONTH , to_dt ))
            days
          , current_date
    FROM (
          SELECT
               from_dt
              , COALESCE(to_dt,CURRENT_DATE) to_dt
          FROM duration
        ) d
    

    <强> Results

    | years | months | days | current_date |
    |-------|--------|------|--------------|
    |    30 |     23 |   82 |   2017-10-19 |
    

    查询3

    ## method using timestampdiff
    SELECT
            d.*
          , TIMESTAMPDIFF(YEAR , from_dt, to_dt )                                                        AS diff_yr
          , TIMESTAMPDIFF(MONTH, from_dt + INTERVAL TIMESTAMPDIFF(YEAR , from_dt, to_dt) YEAR  , to_dt ) AS diff_mn
          , TIMESTAMPDIFF(DAY  , from_dt + INTERVAL TIMESTAMPDIFF(MONTH, from_dt, to_dt) MONTH , to_dt ) AS diff_dy
    FROM (
          SELECT
               from_dt
              , COALESCE(to_dt,CURRENT_DATE) to_dt
              , current_date
          FROM duration
        ) d
    

    <强> Results

    |    from_dt |      to_dt | current_date | diff_yr | diff_mn | diff_dy |
    |------------|------------|--------------|---------|---------|---------|
    | 2011-02-22 | 2017-10-19 |   2017-10-19 |       6 |       7 |      27 |
    | 1999-08-03 | 2005-03-30 |   2017-10-19 |       5 |       7 |      27 |
    | 1982-09-03 | 1988-01-30 |   2017-10-19 |       5 |       4 |      27 |
    | 1965-12-01 | 1980-05-02 |   2017-10-19 |      14 |       5 |       1 |
    

    查询4

    ## testing (method using timestampdiff)
    ## is able to reproduce to_dt ?
    select
          from_dt
        , to_dt
        , from_dt + INTERVAL diff_yr YEAR
                  + INTERVAL diff_mn MONTH
                  + INTERVAL diff_dy DAY
          recalculated_to_dt
        , current_date
    FROM (
          SELECT
                  d.*
                , TIMESTAMPDIFF(YEAR , from_dt, to_dt )                                                                    AS diff_yr
                , TIMESTAMPDIFF(MONTH, from_dt + INTERVAL TIMESTAMPDIFF(YEAR , from_dt, to_dt) YEAR  , to_dt ) AS diff_mn
                , TIMESTAMPDIFF(DAY  , from_dt + INTERVAL TIMESTAMPDIFF(MONTH, from_dt, to_dt) MONTH , to_dt ) AS diff_dy
          FROM (
                SELECT
                     from_dt
                    , COALESCE(to_dt,CURRENT_DATE) to_dt
                FROM duration
              ) d
        ) d2
    

    <强> Results

    |    from_dt |      to_dt | recalculated_to_dt | current_date |
    |------------|------------|--------------------|--------------|
    | 2011-02-22 | 2017-10-19 |         2017-10-19 |   2017-10-19 |
    | 1999-08-03 | 2005-03-30 |         2005-03-30 |   2017-10-19 |
    | 1982-09-03 | 1988-01-30 |         1988-01-30 |   2017-10-19 |
    | 1965-12-01 | 1980-05-02 |         1980-05-02 |   2017-10-19 |
    
    • 30.4375 我相信那是〜(一个世纪的日子)/ 120

答案 1 :(得分:0)

我chaane table nane和两个naness nanes:

find . -type f  | git check-ignore --stdin

看来这就是你想要的......

答案 2 :(得分:0)

SELECT CONCAT(y, ' Years ', m, ' Months ', d, ' Days') as Duration 
FROM(
 SELECT 
   IF(SUM(Month) > 12, SUM(d.Year) + FLOOR(SUM(d.Year/12)), SUM(d.Year)) as y,
   IF(SUM(d.DAY) > 30, FLOOR(MOD(((SUM(d.Month) + FLOOR(SUM(d.Day/30.4375)))), 12)), SUM(d.Month)) as m,
   IF(SUM(d.DAY) > 30, FLOOR(MOD(SUM(d.Day), 30)), SUM(d.Month)) as d
 FROM (
  SELECT 
    TIMESTAMPDIFF( YEAR, a, b ) Year,
    TIMESTAMPDIFF( MONTH, a, b ) % 12 Month,
    FLOOR( TIMESTAMPDIFF( DAY, a, b ) % 30.4375 ) Day
  from dates
  ) as d
) as c

DEMO

答案 3 :(得分:0)

正确的SQL是

选择 求和(d.months)> 12 THEN SUM(d.years)+地板(Sum(d.months / 12))ELSE Sum(d.years)的情况 AS年 ,当SUM(d.days)> 30 THEN FLOOR(MOD((SUM(d.months)+ FLOOR(SUM(d.days / 30.4375))),12))ELSE FLOOR(MOD(SUM(d.months) ),12))结束 AS个月 ,当SUM(d.days)> 30 THEN FLOOR(MOD(SUM(d.days),30))ELSE FLOOR(MOD(SUM(d.days),30))结束时 AS天

从( 选择 TIMESTAMPDIFF(YEAR,from_date,to_date) AS年 ,TIMESTAMPDIFF(MONTH,from_date + INTERVAL TIMESTAMPDIFF(YEAR,from_date,to_date)YEAR,to_date) AS个月 ,TIMESTAMPDIFF(DAY,from_date + INTERVAL TIMESTAMPDIFF(MONTH,from_date,to_date)MONTH,to_date) AS天 来自( 选择 从日期 ,COALESCE(to_date,CURRENT_DATE)到_date 来自user_id ='1'的经验 d2 )d