fcm790 Ответов: 5

Запрос первой и последней записи для определенного идентификатора из таблицы


Я пытаюсь показать первый и последний прием конкретного пациента одновременно. Таким образом, вывод будет выглядеть примерно так: символ “|” ниже представляет собой разделение столбцов.

PatientID | Первый Назначенный День| Первый Назначенный День Статус | Первый Назначенный Визит Тип| Последний Назначенный День| Последний Назначенный День Статус| Последний Визит СПС

Так, например, если я хочу запросить первую и последнюю встречу для PatientID 500, как бы я это сделал?

Таблица, из которой извлекается информация, выглядит следующим образом::

PatientID| APPTDATE| STATUS| VISITTYPE| VISITTIME|LOCATION

Что я уже пробовал:

Выберите PatientID, ApptDate, STATUS, VisitType из ModifiedApptTable
Где PatientID = 500

5 Ответов

Рейтинг:
43

Maciej Los

Я думаю, что вы можете достичь этого, используя JOIN, MIN и MAX таким образом:

--based on example provided in solution #1
SELECT t1.*
FROM @Temp t1 INNER JOIN 
(
	SELECT PatientID, MIN(ApptDate) MinApptDate, MAX(ApptDate) MaxApptDate
	FROM @Temp
	Where PatientID = 500
	GROUP BY PatientID
) t2
 ON t1.ApptDate = t2.MinApptDate OR t1.ApptDate = t2.MaxApptDate


В результате вы получите 2 строки ;)


MadMyche

Я думаю, что собираюсь сделать это как SProc и покончить с этим lol

Рейтинг:
31

MadMyche

Основываясь на вашем исходном содержании, я создал следующую таблицу и заполнил ее. Обратите внимание, что различия в названиях столбцов: это связано с тем, что оба Status и Location выделяются ли специальные/зарезервированные слова в SQL Server и me editor (SSMS)

CREATE TABLE TestData (
  PatientID   int,
  ApptDate    date,
  ApptStatus  varchar(32),
  VisitType   varchar(32),
  VisitTime   time,
  Facility    varchar(32)
)
GO
INSERT TestData VALUES
  (101, '01/01/2001', 'Complete', 'Flu complaint', '08:00', 'TeleMed')
, (101, '01/11/2001', 'Complete', 'Blood draw', '11:30', 'Outpatient Lab')
, (500, '05/01/2005', 'Complete', 'Broken Leg', '08:00', 'ER')
, (500, '06/01/2005', 'Complete', 'XRays', '17:00', 'Radiology')
, (600, '06/06/2005', 'Complete', 'Medical Complaint', '09:00', 'ER')
GO
Способ, которым я собираюсь написать это, будет включать использование 3 переменных в среде SQL. Первый (@PatientID) будет использоваться для определения того, о каком пациенте вы хотите получить данные; а два других (@FirstDate, @LastDate) будут использоваться для определения даты первого и последнего приема.
DECLARE @PatientID INT = 500
DECLARE @FirstDate DATE
DECLARE @LastDate  DATE

SELECT @FirstDate = Min(ApptDate), @LastDate = Max(ApptDate)
FROM   TestData
WHERE  (PatientID = @PatientID)
Теперь, когда у нас есть все эти значения, нам не нужно использовать подзапросы, и это просто становится вопросом использования этих переменных в рамках JOIN оператор для выравнивания результатов в одну строку
SELECT f.PatientID
,      FirstApptDate   = f.ApptDate
,      FirstApptStatus = f.ApptStatus
,      FirstApptType   = f.VisitType
,      LastApptDate    = l.ApptDate
,      LastApptStatus  = l.ApptStatus
,      LastApptType    = l.VisitType
FROM       TestData f
INNER JOIN TestData l   ON f.PatientID = l.PatientID
                       AND f.ApptDate  = @FirstDate
                       AND l.ApptDate  = @LastDate
WHERE  (f.PatientID = @PatientID)


Maciej Los

Более элегантное и эффективное решение заслуживает 5 баллов!

MadMyche

Спасибо...

Рейтинг:
2

kgmmurugesh

select * from (select top 1 PatientID, APPTDATE, STATUS, VISITTYPE from ModifiedApptTable Where PatientID = 500 order by APPTDATE) a union select * from (select top 1 PatientID, APPTDATE, STATUS, VISITTYPE from ModifiedApptTableWhere PatientID = 500 order by APPTDATE desc) b


Рейтинг:
1

MadMyche

Решение, которое вы ищете, будет включать в себя немного больше, чем простой 1-строчный SQL-оператор, и лучший способ будет использовать Min и Max Статистическая функция
MIN (Transact-SQL) - SQL Server | Microsoft Docs[^]
MAX (Transact-SQL) - SQL Server | Microsoft Docs[^]

Как только вы поймете, как получить эти ценности...
1. Вы можете использовать их в подзапросе, чтобы получить только первую информацию appt для этого конкретного пациента
2. Вы можете написать еще одну комбинацию запроса/подзапроса, чтобы получить последнюю информацию о приложении

Итак, теперь у вас есть 2 запроса (w/ subqueries), чтобы получить первую и последнюю информацию appt.
Теперь вы можете JOIN их вместе, чтобы получить информацию все в одном ряду.

В этом образце есть только PatientID и даты в нем... Это не то, что я бы использовал в производстве, но оно полностью функционально. Что он действительно показывает, так это то, как все это можно сделать

DECLARE @Temp Table ( PatientID int, ApptDate date )

INSERT @Temp VALUES
    (101, '01/01/2001'), (101, '01/11/2001'), (500, '05/01/2005'), (500, '06/01/2005'), (600, '06/06/2005')

SELECT f.PatientID
,      FirstApptDate       = f.ApptDate
,      LastApptDate        = l.ApptDate

FROM (
     SELECT PatientID, ApptDate
     FROM   @Temp
     WHERE  ApptDate = (
          SELECT Min(ApptDate)
		FROM   @Temp
		WHERE  PatientID = 500 )         ) as F
INNER JOIN  (
     SELECT PatientID, ApptDate
     FROM   @Temp
     WHERE  ApptDate = (
	     SELECT FirstDate = Max(ApptDate)
          FROM   @Temp
          WHERE PatientID = 500)           ) as L ON  f.PatientID = l.PatientID
WHERE f.PatientID = 500
Для производственного сценария... это было бы заменено хранимой процедурой, которая использовала бы еще несколько переменных и не полагалась бы на все подзапросы


Maciej Los

Что ж... я бы избегал использования нескольких подзапросов из-за производительности запроса. Пожалуйста, смотрите мой ответ.

MadMyche

Никогда не говорил, что это красиво... но все концепции есть ... и я сказал, что не буду использовать его в производстве.

Рейтинг:
0

NEGIN_K

DROP TABLE #TMP 
SELECT [PatientID],
MAX(APPTDATE) M,MIN(APPTDATE) AS MN INTO #TMP
FROM TESTDATA S 
GROUP BY [PatientID];

WITH CTE
AS
(
SELECT T.[PatientID], [ApptDate], [ApptStatus], [VisitType], [VisitTime], [Facility],'MAXdATE'  AS RANGE
FROM TESTDATA T WHERE EXISTS (
SELECT  * FROM #TMP P WHERE P.[PatientID]=T.[PatientID] AND P.M=T.[ApptDate])
UNION ALL
SELECT T.[PatientID], [ApptDate], [ApptStatus], [VisitType], [VisitTime], [Facility],'MINDATE' AS RANGE
FROM TESTDATA T WHERE EXISTS (
SELECT  * FROM #TMP P WHERE P.[PatientID]=T.[PatientID] AND P.MN=T.[ApptDate])
)

SELECT * FROM CTE  WHERE [PatientID]=101