我正在努力以下列方式从mysql获取结果。我在mysql db表中有10条记录,有日期和单位字段。我需要在每个日期都使用单位。
表结构如下,在每个记录中添加今天单位和过去的前一单位:
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
任何帮助将不胜感激。谢谢
答案 0 :(得分:2)
有几种方法可以获得结果集。如果您可以在结果集中使用额外的列以及列的顺序,那么这样的事情是可行的方法。
使用用户变量
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称之为“派生表”)
要删除该额外列,您可以将其包装在另一个查询...
SELECT f.Date
, f.Units_used
FROM (
query from above goes here
) f
ORDER BY f.Date
但同样,删除该列会带来第二次实现该结果集的额外成本。
使用半联接
如果保证每个Date
值都有一行,可以存储为DATE,也可以存储为DATETIME,并将timecomponent设置为常量,例如午夜,并且Date值中没有间隙,和Date定义为DATE或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
如果缺少日期值(间隙),使得前一行没有匹配,则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
答案 1 :(得分:1)
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 |
+----+-------+
答案 2 :(得分:0)
这应该会产生预期的结果。我不知道你的表是如何被调用的所以我把它命名为“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