Как я могу сделать левое внешнее соединение, где у обеих таблиц есть предложение where? - PullRequest
0 голосов
/ 01 апреля 2010

Вот сценарий:

У меня есть 2 таблицы:

CREATE TABLE dbo.API_User
    (
    id int NOT NULL,
    name nvarchar(255) NOT NULL,
    authorization_key varchar(255) NOT NULL,
    is_active bit NOT NULL
    )  ON [PRIMARY]

CREATE TABLE dbo.Single_Sign_On_User
    (
    id int NOT NULL IDENTITY (1, 1),
    API_User_id int NOT NULL,
    external_id varchar(255) NOT NULL,
    user_id int NULL
    )  ON [PRIMARY]

Я пытаюсь вернуть следующее:

  1. is_active для данного ключа авторизации
  2. Single_Sign_On_User.id, который соответствует паре external_id / API_User_id, если она существует, или NULL, если такой пары нет

Когда я пытаюсь выполнить этот запрос:

SELECT Single_Sign_On_User.id, API_User.is_active
FROM API_User LEFT OUTER JOIN
    Single_Sign_On_User ON Single_Sign_On_User.API_User_id = API_User.id
WHERE     
    Single_Sign_On_User.external_id = 'test_ext_id' AND 
    API_User.authorization_key = 'test'

, где существует запись «test» API_User, а записи «test_ext_id» нет, и при отсутствии других значений в любой из таблиц я не получаю никаких записей.

Когда я использую:

SELECT Single_Sign_On_User.id, API_User.is_active
FROM API_User LEFT OUTER JOIN
    Single_Sign_On_User ON Single_Sign_On_User.API_User_id = API_User.id
WHERE     
    API_User.authorization_key = 'test'

Я получаю ожидаемые результаты (NULL, 1), но этот запрос не позволяет мне найти запись «test_ext_id», если она существует, но выдаст мне все записи, связанные с записью «test» API_User.

Как мне получить результаты, которые мне нужны?

Ответы [ 2 ]

3 голосов
/ 01 апреля 2010

Фильтрация по «внешней» таблице »изменяет соединение на INNER.

4 варианта, из которых первые 2 являются лучшими

  • производная таблица

Фильтр внутри производной таблицы

SELECT SSOU.id, API_User.is_active
FROM
    API_User
    LEFT OUTER JOIN
    (
    SELECT id FROM Single_Sign_On_User WHERE external_id = 'test_ext_id'
    ) SSOU  ON SSOU.API_User_id = API_User.id
WHERE     
    API_User.authorization_key = 'test'
  • CTE (вместо производной таблицы) для SQL Server 2005 +

  • фильтр в JOIN

* * Таким образом, тысяча двадцать-одина; * * одна тысяча двадцать-дв
SELECT Single_Sign_On_User.id, API_User.is_active
FROM API_User LEFT OUTER JOIN
    Single_Sign_On_User ON Single_Sign_On_User.API_User_id = API_User.id

    AND Single_Sign_On_User.external_id = 'test_ext_id'

WHERE     
    API_User.authorization_key = 'test'
  • ИЛИ предложение

Таким образом:

SELECT Single_Sign_On_User.id, API_User.is_active
FROM API_User LEFT OUTER JOIN
    Single_Sign_On_User ON Single_Sign_On_User.API_User_id = API_User.id
WHERE     
    (Single_Sign_On_User.external_id = 'test_ext_id' OR Single_Sign_On_User.external_id IS NULL)
    AND
    API_User.authorization_key = 'test'
0 голосов
/ 01 апреля 2010

Я бы использовал пример gbn с условием в LEFT JOIN, но также это эквивалентно ИЛИ и иногда может быть лучше при генерации кода (без надоедливых скобок, чтобы отслеживать с ИЛИ):

SELECT Single_Sign_On_User.id
       ,API_User.is_active
FROM API_User
LEFT OUTER JOIN Single_Sign_On_User
    ON Single_Sign_On_User.API_User_id = API_User.id
WHERE COALESCE(Single_Sign_On_User.external_id, 'test_ext_id') = 'test_ext_id'
    AND API_User.authorization_key = 'test'
...