#sql #sql-server #sql-order-by #greatest-n-per-group #window-functions
#sql #sql-сервер #sql-порядок по #наибольшее число записей на группу #окно-функции
Вопрос:
У меня есть таблица, которая выглядит следующим образом
Я должен выбрать каждую вторую запись для каждого идентификатора пациента, которая дала бы следующий результат (мой последний запрос возвращает этот результат)
Затем я должен выбрать запись с самой старой датой, которая будет следующей (это конечный результат, который я хочу)
Что я сделал до сих пор: у меня есть CTE, который получает все необходимые мне данные
WITH cte
AS
(
SELECT visit.PatientTreatmentVisitID, mat.PatientMatchID,pat.PatientID,visit.RegimenDate AS VisitDate,
ROW_NUMBER() OVER(PARTITION BY mat.PatientMatchID, pat.PatientID ORDER BY visit.VisitDate ASC) AS RowNumber
FROM tblPatient pat INNER JOIN tblPatientMatch mat ON mat.PatientID = pat.PatientID
LEFT JOIN tblPatientTreatmentVisit visit ON visit.PatientID = pat.PatientID
)
Затем я пишу запрос к CTE, но пока я могу вернуть только вторую строку для каждого PatientID
SELECT *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate, RowNumber FROM cte
) as X
WHERE RowNumber = 2
Как мне вернуть запись только с самой старой датой? Возможно, есть функция MIN (), которую я мог бы где-нибудь включить?
Комментарии:
1. Было бы полезно, если бы вы указали, какую СУБД и версию вы используете, например, SQL Server 2008 (или что-то еще)
2. Я использую SQL Server 2016
3. Выделение нас таким жирным шрифтом не облегчает прочтения вопроса. Также в будущем мы предпочитаем, чтобы данные были форматированным текстом, а не изображениями.
Ответ №1:
Если я правильно вас понял, вы можете просто упорядочить свой существующий результирующий набор и сохранить только верхнюю строку.
В стандартном SQL вы бы написали это, используя FETCH
предложение:
SELECT *
FROM (
SELECT
visit.PatientTreatmentVisitID,
mat.PatientMatchID,
pat.PatientID,
visit.RegimenDate AS VisitDate,
ROW_NUMBER() OVER(PARTITION BY mat.PatientMatchID, pat.PatientID ORDER BY visit.VisitDate ASC) AS rn
FROM tblPatient pat
INNER JOIN tblPatientMatch mat ON mat.PatientID = pat.PatientID
LEFT JOIN tblPatientTreatmentVisit visit ON visit.PatientID = pat.PatientID
) t
WHERE rn = 2
ORDER BY VisitDate
OFFSET 0 ROWS FETCH FIRST 1 ROW ONLY
Этот синтаксис поддерживается в Postgres, Oracle, SQL Server (и, возможно, в других базах данных).
Ответ №2:
Если вам нужно получить самую старую дату из всех выбранных дат (каждая вторая строка для каждого идентификатора пациента), вы можете попробовать window function Min:
SELECT * FROM
(
SELECT *, MIN(VisitDate) OVER (Order By VisitDate) MinDate
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate,
RowNumber FROM cte
) as X
WHERE RowNumber = 2
) Y
WHERE VisitDate=MinDate
Или вы можете использовать инструкцию SELECT TOP. SELECT TOP clause
Позволяет ограничить количество строк, возвращаемых в наборе результатов запроса:
SELECT TOP 1 PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate FROM
(
SELECT *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate,
RowNumber FROM cte
) as X
WHERE RowNumber = 2
) Y
ORDER BY VisitDate
Комментарии:
1. Грааф, ты пробовал запрос?
Ответ №3:
Для простоты добавьте order desc
в столбец даты и используйте TOP
для получения только первой строки
SELECT TOP 1 *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate, RowNumber FROM cte
) as X
WHERE RowNumber = 2
order by VisitDate desc