如何在 MySQL 8(如 MSSQL)上使用表达式作为 LAG() 第二个参数?

Posted

技术标签:

【中文标题】如何在 MySQL 8(如 MSSQL)上使用表达式作为 LAG() 第二个参数?【英文标题】:How to use expression as LAG() second parameter on MySQL 8 (like MSSQL)? 【发布时间】:2019-11-06 15:38:13 【问题描述】:

我正在尝试迁移此 SQL SERVER 查询:

SELECT year, sales,   
    LAG(year-2, 2*(SELECT MIN(sales) FROM product_sales), sales/2.0 ) OVER (ORDER BY year) AS no_sense  
FROM product_sales;

dbfiddle link

MySQL 8(相同的查询):

dbfiddle link

不幸的是,我收到了这个错误:

您的 SQL 语法有错误;检查手册 对应于您的 mysql 服务器版本,以便使用正确的语法 '*(SELECT MIN(sales) FROM product_sales), sales/2.0) OVER (ORDER) 附近 BY year) AS no_' 在第 2 行

是否可以将此查询“移植”到 mysql?

提前致谢!

【问题讨论】:

你想完成什么?这在任何数据库中似乎都没有用。 这只是授权框架orm的一个例子 我认为您想使用 LAG() 但不在窗口函数中。您能描述一下您要计算的内容吗/ 我想从 sqlserver 得到同样的结果 【参考方案1】:

注意:此答案基于 Vignesh Kumar A 的 answer。 那么为什么 MySQL 8 不支持 SQL Server 语法已经在他的回答中得到了充分的解释,我选择不解释它。

在 MySQL 8 中,您需要从中进行动态 SQL 查询,因为 LAG() 的偏移量参数不支持 SQL 表达式..

SET @sql = CONCAT("
SELECT
    year
  , sales
  , LAG(year-2,  ",(SELECT FLOOR(MIN(sales)) FROM product_sales),", sales/2.0 ) OVER (ORDER BY year) AS no_sense  
FROM product_sales;
");

PREPARE q FROM @sql;
EXECUTE q;

注意: FLOOR() 可以修复 19874.00 不给出延迟功能的错误。 在场外,您可以重写SET @sql := CONCAT("..") 部分different,只需使用您最了解的写作风格。

结果

| year | sales | no_sense |
| ---- | ----- | -------- |
| 2017 | 55000 | 27500    |
| 2017 | 78000 | 39000    |
| 2017 | 49000 | 24500    |
| 2017 | 32000 | 16000    |
| 2018 | 41000 | 20500    |
| 2018 | 89651 | 44825.5  |
| 2018 | 19874 | 9937     |
| 2018 | 32562 | 16281    |
| 2019 | 87456 | 43728    |
| 2019 | 75000 | 37500    |
| 2019 | 96500 | 48250    |
| 2019 | 85236 | 42618    |

见demo

之所以有效,是因为PREPARE q FROM @sql; 会生成此 SQL。 (Vignesh Kumar A 答案)

SELECT 
   year  
 , sales  
 , LAG(year-2, 19874, sales/2.0 ) OVER (ORDER BY year) AS no_sense
FROM product_sales; 

【讨论】:

非常感谢!我希望这个问题可以在未来几年 MySQL 8 更流行时对人们有所帮助。 “我希望这个问题可以在 MySQL 8 更受欢迎的未来几年对人们有所帮助。” 也许@celsowm 仍然是 Gordon Linoff 的评论 “你想做什么完成?这在任何数据库中似乎都没有用。” 关于你的问题是非常有效的,这并不是很有用..【参考方案2】:

这是因为 LAG 函数中的 offset 参数。在MYSQL 中,偏移量将不接受表达式或列,它只接受正数,而MSSQL 将接受除负数之外的所有值。

MYSQL

offset - offset 是从当前行返回的行数,从中获取值。偏移量必须为零或文字正整数。如果 offset 为零,则 LAG() 函数计算当前行的表达式。如果不指定偏移量,则 LAG() 函数默认使用一个。

MSQSQL

offset - 从当前行返回的行数,从中获取值。如果未指定,default 为 1。offset 可以是列、子查询或其他表达式,其计算结果为正整数或可以隐式转换为 bigint。 offset 不能为负值或解析函数。

也许你可以尝试最大数量的相同查询。

SELECT year, sales,   
    LAG(year-2, 19874, sales/2.0 ) OVER (ORDER BY year) AS no_sense  
FROM product_sales;

FIDDLE

【讨论】:

太可惜了,我试过用@variable但是结果是空的:dbfiddle.uk/…

以上是关于如何在 MySQL 8(如 MSSQL)上使用表达式作为 LAG() 第二个参数?的主要内容,如果未能解决你的问题,请参考以下文章

怎么把mssql改为mysql

mssql 如何初始 id

mssql查询

如何实现mysql和mssql的数据同步

从成本角度来看,在 MySQL 上使用 MSSQL 的理由 [关闭]

MySQL 8.0 新增SQL语法对窗口函数和CTE的支持