在mysql 5.7中将rank()转换为(分区....)

gou*_*geo 2 mysql sql select subquery window-functions

我正在尝试在 mysql 5.7 中转换以下 sql

 SELECT T.STOREID AS STOREID,
           T.ARTID AS ARTID,
           T.TOTAMOUNT,
           MAX(T.HOUR) AS HOUR,
           RANK() OVER (PARTITION BY T.STOREID, T.ARTID
                        ORDER BY T.STOREID, T.ARTID, T.HOUR DESC) AS RN
    FROM T
ORDER BY T.STOREID,
         T.ARTID
Run Code Online (Sandbox Code Playgroud)

这在 oracle 中工作得很好,但在 mysql 中也能工作,因为只有 mysql 8 及更高版本支持此功能。任何人都可以帮助我,以便在 mysql 5.7 中获得相同的结果

GMB*_*GMB 6

首先,关于您的原始查询的一些注意事项:

  • 它不是有效的 SQL;select子句 ( )中有聚合函数max(t.hour),但没有group by子句

  • 子句未优化:它以属于子句一部分的列开头,这是不必要的(我们已经知道分区中的所有行对于这些列order by都具有相同的值)rank()partition by

所以我假设您要重写的查询是:

select 
    t.storeid as storeid,
    t.artid as artid,
    t.totamount,
    t.hour,
    rank() over(partition by t.storeid, t.artid order by t.hour desc) rn
from t
order by t.storeid, t.artid
Run Code Online (Sandbox Code Playgroud)

现在,在 MySQL 5.7 中,一种模拟方法rank()使用相关子查询:

select 
    t.storeid as storeid,
    t.artid as artid,
    t.totamount,
    t.hour,
    (
        select 1 + count(*)
        from t t1
        where 
            t1.storeid = t.storeid 
            and t1.artid = t.artid
            and t1.hour > t.hour

    ) as rn
from t
order by t.storeid, t.artid
Run Code Online (Sandbox Code Playgroud)

请注意,这实际上比窗口函数效率低,因为必须对原始表中的每一行执行子查询。其他解决方案通常涉及用户变量。