mysql 按日期获取单位消耗

edqdpe6u  于 5个月前  发布在  Mysql
关注(0)|答案(4)|浏览(46)

我挣扎着从mysql中得到结果如下。我有10个记录在mysql数据库表有日期和单位字段。我需要得到每个日期使用的单位。
表结构如下,在每条记录中添加今天的单位和过去的前一个单位:

Date        Units  
 ----------  ---------
 10/10/2012   101
 11/10/2012   111
 12/10/2012   121
 13/10/2012   140
 14/10/2012   150
 15/10/2012   155
 16/10/2012   170
 17/10/2012   180
 18/10/2012   185
 19/10/2012   200

字符串
所需的输出将是:

Date        Units  
 ----------  ---------
 10/10/2012   101
 11/10/2012   10
 12/10/2012   10
 13/10/2012   19
 14/10/2012   10
 15/10/2012   5
 16/10/2012   15
 17/10/2012   10
 18/10/2012   5
 19/10/2012   15


任何帮助都将不胜感激。谢谢

avkwfej4

avkwfej41#

有几种方法可以得到结果集。如果你能接受结果集中的一个额外的列,以及列的顺序,那么像这样的方法是可行的。

使用用户变量

SELECT d.Date
     , IF(@prev_units IS NULL
         ,@diff := 0
         ,@diff := d.units - @prev_units
       ) AS `Units_used`
     , @prev_units := d.units AS `Units`
  FROM ( SELECT @prev_units := NULL ) i
  JOIN ( 
         SELECT t.Date, t.Units
           FROM mytable t
          ORDER BY t.Date, t.Units
       ) d

字符串
这将返回指定的结果集,但它也包括Units列。可以过滤掉该列,但由于MySQL处理内联视图的方式(MySQL称之为“派生表”),因此成本更高。
要删除该额外列,可以将其 Package 在另一个查询中...

SELECT f.Date
     , f.Units_used
  FROM (
         query from above goes here
       ) f
 ORDER BY f.Date


但是,再次删除该列会带来第二次具体化该结果集的额外成本。

使用半连接

如果你保证每个Date值都有一行,或者存储为一个日期,或者存储为一个DATETIME,其中时间组件设置为一个常量,比如午夜,并且日期值中没有间隔,并且日期定义为日期或DATETIME数据类型,那么另一个查询将返回特定的结果集:

SELECT t.Date
     , t.Units - s.Units AS Units_Used
  FROM mytable t
  LEFT
  JOIN mytable s
    ON s.Date = t.Date + INTERVAL -1 DAY
  ORDER BY t.Date


如果缺少Date值(间隙),使得没有匹配的前一行,则Units_used将具有NULL值。

使用相关子查询

如果你不能保证没有“缺失的日期”,但是你可以保证一个特定的日期不超过一行,那么另一种方法(通常在性能方面更昂贵)是使用相关的子查询:

SELECT t.Date
     , ( t.Units - (SELECT s.Units 
                      FROM mytable s
                     WHERE s.Date < t.Date
                     ORDER BY s.Date DESC
                     LIMIT 1) 
       ) AS Units_used
  FROM mytable t
 ORDER BY t.Date, t.Units

hfsqlsce

hfsqlsce2#

spencer7593的解决方案会更快,但你也可以这样做.

SELECT * FROM rolling;
+----+-------+
| id | units |
+----+-------+
|  1 |   101 |
|  2 |   111 |
|  3 |   121 |
|  4 |   140 |
|  5 |   150 |
|  6 |   155 |
|  7 |   170 |
|  8 |   180 |
|  9 |   185 |
| 10 |   200 |
+----+-------+

SELECT a.id,COALESCE(a.units - b.units,a.units) units
  FROM 
 ( SELECT x.*
        , COUNT(*) rank
     FROM rolling x
 JOIN rolling y
       ON y.id <= x.id
GROUP
   BY x.id
 ) a     
LEFT
JOIN 
 ( SELECT x.*
        , COUNT(*) rank
     FROM rolling x
 JOIN rolling y
       ON y.id <= x.id
GROUP
   BY x.id
 ) b
ON b.rank= a.rank -1;

    +----+-------+
    | id | units |
    +----+-------+
    |  1 |   101 |
    |  2 |    10 |
    |  3 |    10 |
    |  4 |    19 |
    |  5 |    10 |
    |  6 |     5 |
    |  7 |    15 |
    |  8 |    10 |
    |  9 |     5 |
    | 10 |    15 |
    +----+-------+

字符串

a5g8bdjr

a5g8bdjr3#

这应该给予想要的结果。我不知道你的表是如何命名的,所以我命名它为“tbltest”。创建一个表日期通常是一个坏主意,因为它也指其他事情(函数、数据类型、在字段名或表名中使用fdate字符也是一个坏主意,因为它会使语句不那么独立于数据库(有些数据库区分大小写,有些不区分大小写)。

SELECT
  A.fdate,
  A.units - coalesce(B.units, 0) AS units
FROM
  tbltest A left join tbltest B ON A.fdate = B.fdate + INTERVAL 1 DAY

字符串

jjjwad0x

jjjwad0x4#

SELECT A.units AS current_units,IFNULL(A.units - LAG(A.units)OVER(ORDER BY A.id),A.units)AS difference FROM tbltest A;

相关问题