Если я правильно понял, вы хотите:
- Выберите этих людей
- Кто был инфицирован одним (1) конкретным заболеванием
- Кто лечился одним или несколькими указанными препаратами
- А кто НЕ лечился одним или несколькими указанными другими препаратами
Это можно упростить, преобразовав ваши «потребности в лекарствах» во временную таблицу некоторой формы. Это позволило бы использовать любое количество «хороших» и «плохих» лекарств для опроса. То, что у меня есть ниже, может быть реализовано в виде хранимой процедуры, но если это не вариант, доступно несколько сложных вариантов.
Разбивая шаги:
Сначала , вот как выбираются нужные пациенты. Мы будем использовать это как подзапрос позже:
SELECT [PersonData]
from DISEASE_T di
inner join PERSON_T pe
on pe.Person_Id = di.Person_Id
where di.Disease_Id = [TargetDisease]
and [TimeConstraints]
Секунда , для каждого набора «целевых» препаратов, которые вы вместе AND, создали временную таблицу следующим образом (это синтаксис SQL Server, у Postgres должно быть что-то похожее):
CREATE TABLE #DrugSet
(
Drug_Id [KeyDataType]
,Include int not null
)
Заполните его одной строкой для каждого рассматриваемого вами препарата:
- Drug_Id = препарат, который вы проверяете
- Включите = 1, если человек принимал препарат, и 0, если он не принимал его
и вычислим два значения:
@ GoodDrugs, количество лекарств, которые вы хотите, чтобы пациент принял
@BadDrugs, количество лекарств, которые вы хотите, чтобы пациент не принимал
Теперь сошиваем все вышеперечисленное вместе в следующем запросе:
SELECT pe.[PersonData] -- All the desired columns from PERSON_T and elsewhere
from DRUG_T dr
-- Filter to only include "persons of interest"
inner join (select [PersonData]
from DISEASE_T di
inner join PERSON_T pe
on pe.Person_Id = di.Person_Id
where di.Disease_Id = [TargetDisease]
and [TimeConstraints]) pe
on pe.Person_Id = dr.Person_ID
-- Join with any of the drugs we are intersted in
left outer join #DrugSet ta
on ta.Drug_Id = dr.Drug_Id
group by pe.[PersonData] -- Same as in the SELECT clause
having sum(case ta.Include
when 1 then 1 -- This patient has been given a drug that we're looking to match
else 0 -- This patient has not been given this drug (catches NULLs, too)
end) = @GoodDrugs
and sum(case ta.Include
when 0 then 1 -- This patient has been given this drug that we're NOT looking to match
else 0 -- This patient has not been given this drug (catches NULLs, too)
end) = @BadDrugs
Я намеренно проигнорировал критерии времени, так как вы не вдавались в детали, но добавить их было довольно просто (хотя я надеюсь, что это не самые известные последние слова).
Дальнейшая оптимизация возможна, но многое зависит от данных и других возможных критериев.
Вам нужно будет выполнить это один раз для каждого «набора лекарств» (то есть наборов ИСТИННЫХ или ЛОЖНЫХ лекарств И вместе взятых), объединяя список
с каждым проходом. Возможно, вы могли бы расширить #DrugSet, чтобы учитывать каждый набор препаратов, который вы проверяете, но я не хочу пытаться
код, который без каких-либо серьезных данных для проверки.
* /