предыдущий элемент в списке, упорядоченный по двум столбцам - PullRequest
1 голос
/ 15 февраля 2012

Допустим, у нас есть таблица со столбцами DAY и NUMERO.

Может быть множество строк с одинаковым значением 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, кажется, не разрешает союзс более чем одним столбцом.

Оба решения выглядят слишком тяжелыми для проблемы, кажущейся такой простой ...

Ответы [ 3 ]

4 голосов
/ 15 февраля 2012

ОБНОВЛЕНИЕ

Вот решение, которое действительно дает правильные результаты!

 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
1 голос
/ 16 февраля 2012

Если вы извлекаете предыдущую пару только на основе одной пары, а не пытаетесь выполнить всю таблицу, как на это ссылались другие, вы можете попробовать выполнить следующий простой запрос -

: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
1 голос
/ 15 февраля 2012

Это ванильный запрос, без использования 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...