SQL Выберите одну строку на ключевое поле с несколькими критериями - PullRequest
0 голосов
/ 17 октября 2019

У меня есть ситуация, когда у меня есть таблица с несколькими записями на объект в разные моменты времени, поэтому мне нужно иметь возможность выбрать самую актуальную запись, которая является действительной. В каждой строке также есть флаг Validity. Таким образом, логика, которую я пытаюсь достичь, заключается в следующем: 1001 *

1.Получить все записи, привязанные к определенному ключевому полю

2.Ввести строку, помеченную как действительную

3.Если нет верной строки, вернуть строку с самой высокой датой.

 ID           DataPoint   Shift    Valid     Year
------------ ----------- -------- -------   --------
A43659        776         1                  2019     
A43659        777         3        X         2018
A43659        778         1                  2017
C43649        300         1                  2019
C43649        538         1                  2018
C43649        690         2                  2016

С учетом этих данных конечный результат должен быть

 ID           DataPoint   Shift    Valid     Year
------------ ----------- -------- -------   --------
A43659        777         3        X         2018
C43649        300         1                  2019

Теперь сделать это по одному элементу за раз было бы относительно просто

IF (SELECT COUNT(*) FROM TABLE WHERE ID = 'A43659' AND Valid = 'X') > 0 BEGIN
    SELECT * FROM TABLE WHERE ID = 'A43659' AND Valid = 'X'
END
ELSE
    SELECT TOP 1 * FROM TABLE WHERE ID = A43659 ORDER BY YEAR DESC

Однако я не могу найти хороший способ сделать это без серьезного случая RBAR (или в этом случае, я думаю,это Row By Agonizing Group? RBAG?)

Я пытался придумать способ сделать это, используя over|partition by, но так как в моих реальных данных много точек, я не нашел примера, которыйсохраняет весь ряд.

Ответы [ 2 ]

2 голосов
/ 17 октября 2019

Кажется, что простая задача для ROW_NUMBER, например,

WITH cte as
 (
   SELECT *,
      ROW_NUMBER() 
      OVER (PARTITION BY ID
            ORDER BY Valid DESC, YEAR DESC) AS rn
        -- if there are other values besides X you can switch to
        -- ORDER BY CASE WHEN valid = 'X' then 0 ELSE 1 END, YEAR DESC)
   FROM TABLE
 ) 
select * from cte
where rn = 1 

Кстати, та же логика может быть применена к вашему ТОП-запросу

1 голос
/ 17 октября 2019

Мне нравится решение Дноета.

Однако мне интересно, если этот подход быстрее, чем row_number():

select t.*
from t
where t.year = (select coalesce(max(case when t2.valid = 'X' then t2.year end), max(t2.year))
                from t t2
                where t2.id = t.id
               );

Это может использовать индекс на (id, valid, year).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...