40
| time                | company | quote |
+---------------------+---------+-------+
| 0000-00-00 00:00:00 | GOOGLE  |    40 |
| 2012-07-02 21:28:05 | GOOGLE  |    60 |
| 2012-07-02 21:28:51 | SAP     |    60 |
| 2012-07-02 21:29:05 | SAP     |    20 |

如何在 MySQL 中对这个表进行延迟以打印引号中的差异,例如:

GOOGLE | 20
SAP    | 40  
4

3 回答 3

59

这是我最喜欢的 MySQL hack。

这是您模拟滞后功能的方式:

SET @quot=-1;
select time,company,@quot lag_quote, @quot:=quote curr_quote
  from stocks order by company,time;
  • lag_quote保存前一行引号的值。对于第一行@quot 是-1。
  • curr_quote保存当前行引用的值。

笔记:

  1. order by子句在这里很重要,就像它在常规窗口函数中一样。
  2. 您可能还想使用 lagcompany来确保您正在计算相同的引号中的差异company
  3. 你也可以用同样的方法实现行计数器@cnt:=@cnt+1

这个方案的好处是与其他一些方法(如使用聚合函数、存储过程或在应用程序服务器中处理数据)相比,它在计算上非常精简。

编辑:

现在来回答您以您提到的格式获取结果的问题:

SET @quot=0,@latest=0,company='';
select B.* from (
select A.time,A.change,IF(@comp<>A.company,1,0) as LATEST,@comp:=A.company as company from (
select time,company,quote-@quot as change, @quot:=quote curr_quote
from stocks order by company,time) A
order by company,time desc) B where B.LATEST=1;

嵌套并不相关,因此(计算上)不像看起来(语法上)那么糟糕:)

如果您需要任何帮助,请告诉我。

于 2012-07-03T17:46:41.937 回答
12

从 MySQL 8.0 及以上版本无需模拟LAG. 它是本机支持的,

窗口功能

从在其分区内滞后(先于)当前行 N 行的行返回 expr 的值。如果没有这样的行,则返回值为默认值。例如,如果 N 为 3,则返回值为前两行的默认值。如果缺少 N 或默认值,则默认值分别为 1 和 NULL。

SELECT
     company,
     quote,
     LAG(quote) OVER(PARTITION BY company ORDER BY time) AS prev_quote
FROM tab;

DBFiddle 演示

于 2018-04-06T19:37:00.253 回答
8

为了达到预期的结果,首先您需要找到每家公司的最后一个和倒数第二个时间戳。使用以下查询非常简单:

SELECT c.company, c.mts, max(l.ts) AS lts
  FROM (SELECT company, max(ts) AS mts FROM cq GROUP BY company) AS c
  LEFT JOIN cq l
    ON c.company = l.company AND c.mts > l.ts
 GROUP BY c.company, c.mts;

现在您必须将此子查询与原始表连接以获得所需的结果:

SELECT c.company, l.quote, coalesce(l1.quote, 0),
       (l.quote - coalesce(l1.quote, 0)) AS result
  FROM (SELECT c.company, c.mts, max(l.ts) AS lts
      FROM (SELECT company, max(ts) AS mts FROM cq GROUP BY company) AS c
      LEFT JOIN cq l
        ON c.company = l.company AND c.mts > l.ts
     GROUP BY c.company, c.mts) AS c
  LEFT JOIN cq AS l ON l.company = c.company AND l.ts = c.mts
  LEFT JOIN cq AS l1 ON l1.company = c.company AND l1.ts = c.lts;

您可以在SQL Fiddle上观察结果。

此查询仅使用标准 SQL 功能,应该适用于任何 RDBMS。

于 2012-07-03T18:22:10.983 回答