Сложный SQL-запрос, может быть, какое-то соединение будет работать? - PullRequest
4 голосов
/ 29 марта 2012

У меня есть SQL-запрос, который я пытаюсь написать, но я не совсем уверен, как заставить его работать.

У меня есть три таблицы: "s", "t" и"st" (это карта между "s" и "t".

table s
=======
primary key sID   |   val
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
       a              0
       b              1
       c              5
       d              6
       e              7



table t
=======
primary key tID   |   val
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
      nul               -1
      bbb                2
      ccc                3
      ddd                4



table st
========
foreign key sID   |  foreign key tID
(unique)          |  (multiple sID to one tID, meaning tID is not unique)
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
       a                    ddd
       b                    ccc
       c                    nul
       d                    ccc
       e                    bbb

Итак, все 's' должны быть сопоставлены с 't', но те, которые не находятся в реальномВместо этого 't' сопоставляется с значением по умолчанию / null 't' (nul).

Значения val уникальны как для 's', так и для 't', что означает, что если таблица 's' имеет 1, тотаблица 't' не может иметь 1.


Так что моя проблема заключается в следующем:

При заданном наборе значений (которое может быть либо 's'или 't'), мне нужно получить sID и tID в таблице 'st' соответствующих идентификаторов. Проблема в том, что если в наборе есть буква 's', а в наборе нет 't', то янужно получить значения (sID, 'nul'), а не (sID, tID).

Например, учитывая значения (3, 1, 6), он вернет пары: (b, ccc); (d, ccc);

Учитывая значения (0,4), она вернет пару: (a, ddd)

Однако, учитывая значение valИбо (6), он должен был бы вернуть (d, nul ), так как val 3 (что соответствует ccc, которому соответствует d) не входит в набор.Я не нуждаюсь в null 's', просто null 't'.


Я думал об использовании следующего утверждения, но это не поможет мне с возвратом "id, nul", еслив наборе только «s», но не «t».

SELECT st.sID, st.tID FROM t, st WHERE t.tID=st.tID AND (t.val=%_VAL1_% OR t.val=%_VAL_2 OR ......);

Это дает мне все, что имеет «t» и «s» в наборе (на самом деле это дает мне все »s 'связан с любым' t 'из набора), но он не дает мне "s", которые сами по себе.

Возможно, я мог бы постобработать все, что находится в "s", ноне в 'st', но я хотел бы избежать этого, если это возможно.

У кого-нибудь есть какие-либо предложения?Я довольно застрял.

Спасибо!

(примечание: s, t и st не мои настоящие имена таблиц, не волнуйтесь. Кроме того, первичные ключина самом деле текстовые идентификаторы GUID, к сожалению, но я попытался упростить их различие)

Ответы [ 2 ]

3 голосов
/ 29 марта 2012

Вот что вы хотите:

SELECT s.sID, t.tID
FROM st
    LEFT JOIN s
        ON s.sID = st.sID AND s.val IN (6)
    LEFT JOIN t
        ON t.tID = st.tID AND t.val IN (6)
WHERE NOT(s.sid IS NULL AND t.tid IS NULL)

Вот SQLFiddle , который подтверждает его для всех 3 сценариев . Вы должны иметь таблицу сопоставления в качестве основной, так как результирующий набор взят из таблиц, которые могут быть нулевыми.

Хотя это очень странная логика. Обычно, если сопоставление не попадает в отношение «многие ко многим», вы просто возвращаете 0 строк, а не частичное ....

Если вы хотите отменить дубликаты, которые могут возникнуть из-за нескольких пропусков отображения (ноль в одном столбце), добавьте DISTINCT. Как это:

SELECT DISTINCT s.sID, t.tID
FROM st
    LEFT JOIN s
        ON s.sID = st.sID AND s.val IN (6)
    LEFT JOIN t
        ON t.tID = st.tID AND t.val IN (6)
WHERE NOT(s.sid IS NULL AND t.tid IS NULL)

Вот скрипка, которая показывает дублирование

А вот тот, который исправляет это

И, наконец, на основе последнего обновления. Если вы хотите, чтобы какие-либо столбцы NULL были исключены, просто сделайте INNER JOIN, и вы можете затем удалить проверку NULL, поскольку вы не получите двойные NULL сейчас. ... Не стесняйтесь удалять отличительные, если вы хотите несколько sID|NULL результатов.

SELECT DISTINCT s.sID, t.tID
FROM st
    JOIN s
        ON s.sID = st.sID AND s.val IN (6)
    LEFT JOIN t
        ON t.tID = st.tID AND t.val IN (6)

Вот SQLFiddle

0 голосов
/ 29 марта 2012

Вы ищете LEFT JOIN:

SELECT s.sid AS sid, t.tid AS tid
  FROM s
  LEFT JOIN st
    ON s.sid = st.sid
  LEFT JOIN t
    ON t.tid = st.tid
WHERE s.val IN (3, 1, 6)
  AND t.val IN (3, 1, 6)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...