Выберите все записи, которых еще нет в наборе записей - PullRequest
2 голосов
/ 19 сентября 2011

База данных, с которой я работаю в настоящее время, имеет две таблицы, одна из которых содержит атрибут "contact_person". Этот атрибут сравнивается с несколькими атрибутами (, а не кортежами! ) в другой таблице, которые называются от «contact1» до «contact4», чтобы определить, какие другие атрибуты отображать из второй таблицы (то есть «email1» - «email4» «). Таким образом, первая таблица содержит только контактное лицо, а вторая - данные фактического адреса для нескольких контактных лиц (опять-таки, все они подряд или один кортеж). Не говорите мне, что это не правильный дизайн базы данных - я должен работать с тем, что мне дали -.-

Чтобы получить правильные контактные данные, я решил выполнить выборку для каждого сравнения и объединить их. Это работает нормально и выполняется достаточно хорошо для приложения, которое выполняет запрос. Выглядит очень упрощенно, примерно так:

SELECT contact1, email1, phone1 FROM T1,T2 WHERE contact_person = contact1
UNION ALL
SELECT contact2, email2, phone2 FROM T1,T2 WHERE contact_person = contact2
UNION ALL
SELECT contact3, email3, phone3 FROM T1,T2 WHERE contact_person = contact3
UNION ALL
SELECT contact4, email4, phone4 FROM T1,T2 WHERE contact_person = contact4

Теперь, из-за некорректных и не проверенных на ошибки запросов INSERT, возможно, что "contact_person" равен NULL или пустой строке или что любой из атрибутов "contactN" равен NULL. Поэтому мне нужен еще один запрос SELECT, который отображает все записи, которые находятся в базе данных, но еще не находятся в наборе записей .

На данном примере это может быть достигнуто с помощью чего-то подобного этому:

UNION
SELECT contact_person, 'N/A', 'N/A' FROM T1,T2

В реальном запросе мне (нужно) сделать много форматирования "contact_person" и "contactN", поэтому простое выполнение UNION (без ALL, поэтому равные записи исключаются) не сработает (contactN на самом деле значение для нескольких полей и форматирование не согласованы, поэтому записи, возвращаемые последним запросом, могут отличаться от записей выше даже для одной и той же записи в базе данных). Кроме того, запрос уже настолько огромен, что невозможно использовать противоположность первого запроса для исключения его записей, например:

UNION ALL
SELECT contact_person, 'N/A', 'N/A' FROM T1,T2
    WHERE contact_person <> contact1
    AND contact_person <> contact2
    AND contact_person <> contact3
    AND contact_person <> contact4

Так есть ли другой способ отобразить все записи, которые не были выбраны в самом первом запросе, опубликованном выше? Может быть, каким-то образом запустив подзапрос (ofc существует UID для возвращенных записей - я просто не знаю, как работать с ним в этом контексте)? Мог ли самый первый запрос быть написан более простым способом?

Ответы [ 2 ]

2 голосов
/ 19 сентября 2011
;WITH cp AS
(
    -- strongly recommend appropriate table prefixes in select list:
    SELECT UID, contact1, email1, phone1 
    -- also strongly recommend proper inner joins:
        FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact1
    UNION ALL
    SELECT UID, contact2, email2, phone2 
        FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact2
    UNION ALL
    SELECT UID, contact3, email3, phone3
        FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact3
    UNION ALL
    SELECT UID, contact4, email4, phone4 
        FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact4
)
SELECT contact1, email1, phone1 FROM cp
UNION ALL
SELECT t1.contact_person, 'N/A', 'N/A'
FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact1
WHERE UID NOT IN (SELECT UID FROM cp);

Вы также можете рассмотреть более нормализованный / реляционный дизайн?

1 голос
/ 20 сентября 2011

В качестве альтернативы вы можете сначала нормализовать T2, а затем присоединиться к нему:

WITH normalisedT2 AS (
  SELECT
    contact = CASE x.n
      WHEN 1 THEN T2.contact1
      WHEN 2 THEN T2.contact2
      WHEN 3 THEN T2.contact3
      WHEN 4 THEN T2.contact4
    END,
    email = CASE x.n
      WHEN 1 THEN T2.email1
      WHEN 2 THEN T2.email2
      WHEN 3 THEN T2.email3
      WHEN 4 THEN T2.email4
    END,
    phone = CASE x.n
      WHEN 1 THEN T2.phone1
      WHEN 2 THEN T2.phone2
      WHEN 3 THEN T2.phone3
      WHEN 4 THEN T2.phone4
    END
  FROM T2
    CROSS JOIN (
      SELECT 1 UNION ALL
      SELECT 2 UNION ALL
      SELECT 3 UNION ALL
      SELECT 4
    ) x (n)
)
SELECT
  contact = T1.contact_person,
  email   = COALESCE(T2.email, 'N/A'),
  phone   = COALESCE(T2.phone, 'N/A')
FROM T1
  LEFT JOIN normalisedT2 T2 ON T1.contact_person = T2.contact
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...