窗口函数 ROW_NUMBER() 使用变量 RUNNING TOTAL 更改处理 ORDER BY

Posted

技术标签:

【中文标题】窗口函数 ROW_NUMBER() 使用变量 RUNNING TOTAL 更改处理 ORDER BY【英文标题】:window Function ROW_NUMBER() changes processing ORDER BY with variable RUNNING TOTAL 【发布时间】:2020-06-11 17:16:43 【问题描述】:

当我使用窗口函数 ROW_NUMBER() 添加列时,我看到订单发生了变化。

结果是不正确的运行总计。 (@ONorderQTYrunner)

谁能解释为什么 ROW_NUMBER() 会改变排序顺序并导致运行总计错误?

下面的查询(使用 ROW_NUMBER())正在为第 1 行和第 2 行返回意外的 RUNNINGtotal 值:

1  57   A-123   69  4000    2020-06-10  4500
2  32   A-123   67  500     2020-07-01  500
3  59   A-123   69  2000    2020-07-15  6500
4  60   A-123   69  2000    2020-08-15  8500

没有 ROW_NUMBER() 会返回这个,正如我所料:

57  A-123   69  4000    2020-06-10  4000
32  A-123   67  500     2020-07-01  4500
59  A-123   69  2000    2020-07-15  6500
60  A-123   69  2000    2020-08-15  8500
CREATE TABLE IF NOT EXISTS `PURCHASEorders` (
  `UniKey` int(11) NOT NULL AUTO_INCREMENT,
  `PARTnumber` varchar(255) DEFAULT NULL,
  `POnumber` varchar(255) NOT NULL,
  `QTY` double DEFAULT 0,
  `DOCKdate` date DEFAULT NULL,
   PRIMARY KEY (`UniKey`),
   KEY `PartNumber` (`PARTnumber`),
   KEY `POnumber` (`POnumber`)
) DEFAULT CHARSET=utf8;
INSERT INTO `PURCHASEorders` (`UniKey`, `PARTnumber`,`POnumber`, `QTY`, `DOCKdate`) VALUES
  ('32', 'A-123', 67, 500, '2020-07-01 12:00:00'),
  ('57', 'A-123', 69, 4000,'2020-06-10 12:00:00'),
  ('59', 'A-123', 69, 2000,'2020-07-15 12:00:00'),
  ('60', 'A-123', 69, 2000,'2020-08-15 12:00:00');
SET @PARTnumber = 'A-123';
SET @ONorderQTYrunner =0;

SELECT DISTINCT 
    ROW_NUMBER() OVER(ORDER BY DOCKdate ASC) AS ONorderROWindex,
    PO.UniKey,
    PO.PARTnumber,
    PO.POnumber,
    PO.QTY,
    PO.DOCKdate,
    @ONorderQTYrunner:= @ONorderQTYrunner + PO.QTY AS RUNNINGtotal
FROM PURCHASEorders PO
WHERE PO.PARTnumber = @PARTnumber 
ORDER BY PO.DOCKdate ASC

编辑: 遵循 Gordon Linoff 的建议,使用 this 代替内联变量赋值已纠正了该问题:

SUM(PO.QTY) OVER (ORDER BY PO.DOCKdate) as RUNNINGtotalfollowing 

已更正 RUNNING 总结果:

1  57   A-123   69  4000    2020-06-10  4000
2  32   A-123   67  500     2020-07-01  4500
3  59   A-123   69  2000    2020-07-15  6500
4  60   A-123   69  2000    2020-08-15  8500

结果,问题的根本原因: 不推荐使用的内联变量赋值。 注意:这是 mysql 和 MariaDB 中的问题

【问题讨论】:

【参考方案1】:

MySQL SELECT 语句中的变量赋值现已弃用。使用适当的累积和:

SELECT DISTINCT 
       ROW_NUMBER() OVER (ORDER BY DOCKdate ASC) AS ONorderROWindex,
       PO.UniKey, PO.PARTnumber, PO.POnumber, PO.QTY, PO.DOCKdate,
       SUM(PO.QTY) OVER (ORDER BY PO.DOCKdate) as RUNNINGtotal
FROM PURCHASEorders PO
WHERE PO.PARTnumber = @PARTnumber 
ORDER BY PO.DOCKdate ASC;

我怀疑SELECT DISTINCT 是否真的需要,但那将是另一回事。

【讨论】:

使用您的建议,将“SUM(PO.QTY) OVER (ORDER BY PO.DOCKdate) 添加为 RUNNINGtotal”我得到了正确的运行总数,但 ONorderROWindex 不是按 DOCKdate 排序的。跨度> @gcronin774 。 . .它当然应该是。 ROW_NUMBER() 有一个 ORDER BY 子句。 DBfiddle 不适用于 MySQL 8,但它绝对适用于 MariaDB:dbfiddle.uk/…. 你说得对,戈登。我误读了我的数据和我的例子。该问题已被编辑以阐明解决方案。 @gcronin774 。 . .如果这确实回答了您的问题,您应该接受答案。

以上是关于窗口函数 ROW_NUMBER() 使用变量 RUNNING TOTAL 更改处理 ORDER BY的主要内容,如果未能解决你的问题,请参考以下文章

使用 ROW_NUMBER() 窗口函数选择行

使用MySQL会话变量实现窗口函数

为啥将 ROW_NUMBER 定义为窗口函数?

使用ROW_NUMBER()窗口功能选择行

前 MariaDB 版本中的 Row_Number() 窗口函数

窗口函数 ROW_NUMBER