模拟MySQL中的滞后函数

时间:2012-07-03 01:56:12

标签: 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 |

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

GOOGLE | 20
SAP    | 40  

3 个答案:

答案 0 :(得分:45)

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

这是模拟滞后函数的方法:

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. 您可能还希望对company使用滞后,以确保计算相同company的引号差异。
  3. 您也可以采用@cnt:=@cnt+1
  4. 相同的方式实施行计数器

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

    编辑:

    现在回答你以你提到的格式获得结果的问题:

    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;
    

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

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

答案 1 :(得分:6)

从MySQL 8.0及更高版本开始,无需模拟SELECT company, quote, LAG(quote) OVER(PARTITION BY company ORDER BY time) AS prev_quote FROM tab; 。它原生支持,

  

Window Function

     

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

os.chdir('/Users/user/Desktop/Text_folder')

<强> DBFiddle Demo

答案 2 :(得分:3)

要获得所需的结果,首先需要查找每个公司的上一个和下一个时间戳。使用以下查询非常简单:

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上运行。