假设我们有一个包含DAY和NUMERO列的表。
可以有许多行具有相同的DAY值,但NUMERO始终是唯一的。
在按DAY,NUMERO排序的列表中,最有效的方法是什么?
我精确地说,我需要这个mysql,我不想添加特定的索引(这就是为什么我不简单地使用DAY和NUMERO的线性函数的原因)。
这是一个有序的测试用例:
DAY | NUMERO
1 | 11
1 | 12
1 | 15
4 | 7
4 | 9
4 | 14
5 | 8
6 | 10
6 | 19
我的请求必须这样做:
(1,11)=>无
(1,15)=>(1,12)
(4,7)=>(1,15)
(4,9)=>(4,7)
(4,14)=>(4,9)
编辑:
我目前最好的解决方案是有两个连续的查询:
select * from item where day=? and numero<? order by day desc, numero desc limit 1;
select * from item where day<? order by day desc, numero desc limit 1;
如果第一个查询给出了结果,我就不必运行第二个查询了。
类似的解决方案是使用联合,但mysql似乎不会授权具有多个列的联合。
对于一个看起来如此简单的问题来说,这两种解决方案看起来都太重了。。。
更新
这里有一个解决方案,它实际上给出了正确的结果!
SELECT T1.day,
T1.numero,
COALESCE(MAX(T2.[day]), MAX(T3.[day])) AS prev_day,
COALESCE(MAX(T2.numero), MAX(T3.numero)) AS prev_numero
FROM @table AS T1
LEFT JOIN @table AS T2 ON
(
T2.[day] = T1.[day] AND T2.numero < T1.numero
)
LEFT JOIN @table AS T3 ON
(
T3.[day] < T1.[day]
AND NOT EXISTS(
SELECT *
FROM @table AS T4
WHERE T4.[day] > T3.[day] AND T4.[day] < T1.[day]
)
)
-- Add where clause like so to get specific values
-- WHERE T1.day = 4 AND T1.numero = 7
GROUP BY T1.day, T1.numero
ORDER BY T1.day, T1.numero
结果:
day numero prev_day prev_numero
----------- ----------- ----------- -----------
1 11 NULL NULL
1 12 1 11
1 15 1 12
4 7 1 15
4 9 4 7
4 11 4 9
5 8 4 11
6 10 5 8
6 19 6 10
如果您只基于单个对检索前一对,而不是像其他人所暗示的那样尝试整个表,那么您可以尝试以下简单的查询-
:day = 4
:numero = 9
SELECT day, numero
FROM table
WHERE (day = :day AND numero < :numero)
OR (day < :day)
ORDER BY day DESC, numero DESC
LIMIT 1
这是一个普通查询,避免了CTE、聚合或窗口函数。
-- (a Before b) := (a.day < b.day
-- OR (a.day = b.day AND a.numero < b.numero))
SELECT d1.day AS DAY
, d1.numero AS numero
, d0.day AS day0
, d0.numero AS numero0
FROM tmp.lutser d1
LEFT JOIN tmp.lutser d0
ON (d0.day < d1.day OR (d0.day = d1.day AND d0.numero < d1.numero ))
WHERE NOT EXISTS (SELECT *
FROM tmp.lutser d
WHERE (dx.day < d1.day OR (dx.day = d1.day AND dx.numero < d1.numero ))
AND (dx.day > d0.day OR (dx.day = d0.day AND dx.numero > d0.numero ))
)
ORDER BY day,numero
;
作为参考,这是使用窗口函数的查询:
SELECT day
, numero
, lag(day) OVER (w1)
, lag(numero) OVER (w1)
FROM tmp.lutser
WINDOW w1 AS (ORDER BY day, numero)
;
结果:
day | numero | day0 | numero0
-----+--------+------+---------
1 | 11 | |
1 | 12 | 1 | 11
1 | 15 | 1 | 12
4 | 7 | 1 | 15
4 | 9 | 4 | 7
4 | 11 | 4 | 9
5 | 8 | 4 | 11
6 | 10 | 5 | 8
6 | 19 | 6 | 10
(9 rows)