Как бы я написал этот запрос SQL? - PullRequest
0 голосов
/ 17 сентября 2010

У меня есть следующие таблицы:

PERSON_T              DISEASE_T               DRUG_T
=========             ==========              ========
PERSON_ID             DISEASE_ID              DRUG_ID
GENDER                PERSON_ID               PERSON_ID
NAME                  DISEASE_START_DATE      DRUG_START_DATE
                      DISEASE_END_DATE        DRUG_END_DATE

Я хочу написать запрос, который принимает ввод идентификатора болезни и возвращает одну строку для каждого человека в базе данных со столбцом для пола, aколонка для того, было ли у них когда-либо заболевание, и колонка для каждого лекарства, которая указывает, принимали ли они лекарство до заражения.IE true будет означать drug_start_date <болезнь_старт_дата.Ложь будет означать drug_start_date> sick_start_date или человек никогда не принимал этот конкретный препарат.

В настоящее время мы извлекаем все данные из базы данных и используем Java для создания двумерного массива со всеми этими значениями.Мы расследуем перемещение этой логики в базу данных.Можно ли создать запрос, который будет возвращать набор результатов, как я хочу, или мне нужно будет создать хранимую процедуру?Мы используем Postgres, но я предполагаю, что ответ SQL для другой базы данных легко перевести на Postgres.

Ответы [ 2 ]

3 голосов
/ 17 сентября 2010

На основании предоставленной информации:

   SELECT p.name,
          p.gender,
          CASE WHEN d.disease_id IS NULL THEN 'N' ELSE 'Y' END AS had_disease,
          dt.drug_id
     FROM PERSON p
LEFT JOIN DISEASE d ON d.person_id = p.person_id
                   AND d.disease_id = ?
LEFT JOIN DRUG_T dt ON dt.person_id = p.person_id
                   AND dt.drug_start_date < d.disease_start_date

.. но будет много строк, которые будут выглядеть дублированными, за исключением столбца drug_id.

1 голос
/ 17 сентября 2010

По сути, вы хотите создать запрос кросс-таблица с наркотиками.Несмотря на то, что существует множество инструментов OLAP, которые могут делать подобные вещи (среди других видов нарезки и нарезки данных), сделать что-то подобное в традиционном SQL нелегко (и, в общем, невозможно обойтись безкакой-то процедурный синтаксис во всех, кроме простейших сценариев).

По сути, у вас есть два варианта, когда вы делаете это с SQL (ну, точнее, у вас есть опция одна , а другая более сложнаяно гибкая опция, которая вытекает из него):

  1. Используйте серию операторов CASE в своем запросе, чтобы получить столбцы, представляющие каждый отдельный препарат.Это требует заблаговременного знания списка значений переменных (то есть лекарств)
  2. Использование процедурного языка SQL, такого как T-SQL, для динамического построения запроса, использующего операторы case, как описановыше, но наряду с получением этого списка значений из самих данных.

Два варианта по сути делают одно и то же, вы просто торгуете простотой и удобством обслуживания для гибкости во втором варианте.

Например, используя опцию 1:

select
    p.NAME,
    p.GENDER,
    (case when d.DISEASE_ID is null then 0 else 1 end) as HAD_DISEASE,
    (case when sum(case when dr.DRUG_ID = 1 then 1 else 0 end) > 0 then 1 else 0 end) as TOOK_DRUG_1,
    (case when sum(case when dr.DRUG_ID = 2 then 1 else 0 end) > 0 then 1 else 0 end) as TOOK_DRUG_2,
    (case when sum(case when dr.DRUG_ID = 3 then 1 else 0 end) > 0 then 1 else 0 end) as TOOK_DRUG_3

from PERSON_T p

left join DISEASE_T d on d.PERSON_ID = p.PERSON_ID and d.DISEASE_ID = @DiseaseId
left join DRUG_T dr on dr.PERSON_ID = p.PERSON_ID and dr.DRUG_START_DATE < d.DISEASE_START_DATE

group by p.PERSON_ID, p.NAME, p.GENDER, d.DISEASE_ID

Как вы можете сказать, это становится немного трудоемким, когда вы выходите за пределы нескольких потенциальных значений.

Другой вариант - построить этот запрос динамически.Я не знаю PostgreSQL и какие, если таковые имеются, процедурные возможности у него есть, но общая процедура будет такой:

  1. Соберите список потенциальных DRUG_ID значений вместе с именами для столбцов
  2. Подготовьте три строковых значения: префикс SQL (все до первого оператора CASE, связанного с наркотиками, SQL stuffix (все после последнего оператора CASE, связанного с наркотиками) и динамическая часть
  3. Создайте динамическую часть, объединив операторы CASE на основе ранее полученного списка
  4. Объедините их в один (надеюсь, допустимый) оператор SQL и выполните
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...