模拟MySQL中的滞后函数

jav*_*anx 34 mysql sql sliding-window

| 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 |
Run Code Online (Sandbox Code Playgroud)

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

GOOGLE | 20
SAP    | 40  
Run Code Online (Sandbox Code Playgroud)

Doj*_*ojo 49

这是我最喜欢的MySQL黑客攻击.

这就是你如何模拟滞后函数:

SET @quot=-1;
select time,company,@quot lag_quote, @quot:=quote curr_quote
  from stocks order by company,time;
Run Code Online (Sandbox Code Playgroud)
  • lag_quote保存上一行引用的值.第一行@quot是-1.
  • curr_quote 保存当前行的引用值.

笔记:

  1. order by 这里的子句很重要,就像它在常规窗口函数中一样.
  2. 您可能还希望使用滞后,company以确保您计算相同的引号差异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;
Run Code Online (Sandbox Code Playgroud)

嵌套不是相关的,所以不像它看起来那么糟糕(计算上)(语法上):)

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

  • @javanx您好,我是SQL Fiddle的作者.您提到的错误消息实际上是我处理某些类型的MySQL查询的方式中的错误.感谢您的留言,我已经认识到了这一点,并制定了解决方案来解决问题(请参阅此处,例如:http://sqlfiddle.com/#!2/4f8a1/2).谢谢! (10认同)
  • **注意** 您必须保持变量的数据类型与您尝试滞后的数据类型一致。EG,如果你想累加一个FLOAT字段,你必须将你的变量初始化为`@quot=0.0`,否则它将不起作用。我花了一分钟才弄清楚这一点! (2认同)

Luk*_*zda 10

从MySQL 8.0及更高版本开始,无需模拟LAG.它本机支持,

窗口功能:

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

SELECT
     company,
     quote,
     LAG(quote) OVER(PARTITION BY company ORDER BY time) AS prev_quote
FROM tab;
Run Code Online (Sandbox Code Playgroud)

DBFiddle演示


vye*_*rov 7

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

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;
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

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

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