#sql #ms-access #join #greatest-n-per-group
#sql #ms-access #Присоединиться #наибольшее число пользователей на группу
Вопрос:
Я хочу объединить таблицы в MS Access таким образом, чтобы он извлекал только последнюю запись из одной из таблиц. Я просмотрел другие решения, доступные на сайте, но обнаружил, что они работают только для других версий SQL. Вот упрощенная версия моих данных:
Таблица PatientInfo:
----- ------
| ID | Name |
----- ------
| 1 | John |
| 2 | Tom |
| 3 | Anna |
----- ------
Таблица встреч
---- -----------
| ID | Date |
---- -----------
| 1 | 5/5/2001 |
| 1 | 10/5/2012 |
| 1 | 4/20/2018 |
| 2 | 4/5/1999 |
| 2 | 8/8/2010 |
| 2 | 4/9/1982 |
| 3 | 7/3/1997 |
| 3 | 6/4/2015 |
| 3 | 3/4/2017 |
---- -----------
И вот упрощенная версия результатов, которые мне нужны после объединения:
---- ------ ------------
| ID | Name | Date |
---- ------ ------------
| 1 | John | 4/20/2018 |
| 2 | Tom | 8/8/2010 |
| 3 | Anna | 3/4/2017 |
---- ------ ------------
Заранее спасибо за чтение и за вашу помощь.
Ответ №1:
Вы можете использовать агрегирование и JOIN
:
select pi.id, pi.name, max(a.date)
from appointments as a inner join
patientinfo as pi
on a.id = pi.id
group by pi.id, pi.name;
Ответ №2:
что-то вроде этого: выберите P.ID , P.name , макс (A.Дата) как Dt из PatientInfo P внутренние назначения соединения A на P.ID=A.Группировка идентификаторов по P.ID , P.name
Ответ №3:
Оба ответа Bing и Гордона работают, если вашей сводной таблице требуется только одно поле (максимальное (дата)), но становится сложнее, если вы также хотите сообщить о других полях из объединенной таблицы, поскольку вам нужно будет включить их либо в качестве агрегированного поля, либо сгруппировать по ним. Например, если вы хотите, чтобы ваше резюме также включало оценку, которую они получили на последнем приеме, ГРУППИРОВАТЬ ПО-другому.
Более универсальной структурой может быть что-то вроде
SELECT Patient.ID, Patient.Name, Appointment.Date, Appointment.Assessment
FROM Patient INNER JOIN Appointment ON Patient.ID=Appointment.ID
WHERE Appointment.Date = (SELECT Max(Appointment.Date) FROM Appointment WHERE Appointment.ID = Patient.ID)
;
Кроме того, вы можете подумать, следует ли использовать поле с именем ‘ID’ для ссылки на идентификатор другой таблицы (в данном случае Apppintment.Поле ID относится к Patient.ID ). Вы можете сделать свою базу данных более читаемой, если оставите поле «ID» в качестве идентификатора, специфичного для этой таблицы, и будете ссылаться на это поле в других таблицах как OtherTableID или аналогичный, т.Е. PatientID в данном случае. Или пройдите весь путь и включите имя фактической таблицы в ее собственное поле ID.
Отредактировано после комментария:
Не совсем уверен, почему это приведет к сбою. Я только что выполнил эквивалентный запрос к имеющимся у меня 2 таблицам, каждая из которых содержит около 10 000 записей, и это было довольно мгновенно. Являются ли ваши поля идентификаторов (i) уникальными номерами и (ii) индексированными? Другая структура, которая должна делать то же самое (адаптированная для ваших имен полей и предполагающая, что в назначениях есть поле идентификатора, которое является уникальным), будет выглядеть примерно так:
SELECT PatientInfo.UID, PatientInfo.Name, Appointments.StartDateTime, Appointments.Assessment
FROM PatientInfo INNER JOIN Appointments ON PatientInfo_UID = Appointments.PatientFID
WHERE Appointments.ID = (SELECT TOP 1 ID FROM Appointments WHERE Appointments.PatientFID = PatientInfo_UID ORDER BY StartDateTime DESC)
;
Но это начинает выглядеть немного надуманным. Для моих данных они оба дают одинаковый результат (как и должны!) и оба почти мгновенные.
Всегда сложно устранить неполадки при сбое Access — я думаю, вы не видите кодов ошибок или подобных? Это относится к собственной базе данных .accdb или к другому серверу?
Комментарии:
1. Мне нравится предложенный вами запрос, поскольку я хотел бы сообщить и о других полях, но я работаю с более чем 60 000 строк, и ваше предложение приводит к сбою Access. Есть предложения? Вот код:
SELECT PatientInfo.Patient_UID, PatientInfo.LastName, PatientInfo.FirstName, PatientInfo.Email, PatientInfo.Deceased, Appointments.StartDateTime FROM PatientInfo INNER JOIN Appointments ON PatientInfo.Patient_UID=Appointments.PatientFID WHERE Appointments.StartDateTime = (SELECT Max(Appointments.StartDateTime) FROM Appointments WHERE Appointments.PatientFID = PatientInfo.Patient_UID) ;