В офисе есть более старший разработчик SQL (DBA), который сказал мне, что во всех левых соединениях моего сценария я должен обрабатывать сценарий, в котором столбец соединения левой таблицы, возможно, равен нулю, в противном случае я должны использовать внутренние соединения. Теперь, будучи новичком, я могу ошибаться здесь, но я не вижу его смысла и оставил меня без нужды в замешательстве.
Его объяснение было таковым, если только столбец не обнуляем, либо я должен
- используйте
ISNULL(LeftTable.ColumnA,<replacement value here>)
в предложении ON или
- обрабатывать нулевые значения в предложении ON или
Предложение WHERE, добавив
AND LeftTable.ColumnA IS NOT NULL
или AND LeftTable.ColumnA IS NULL
.
Я думал, что в этом нет необходимости, поскольку каждый использует LEFT JOIN, если не возражает против возврата пустых строк из правой таблицы, если значения правого столбца объединения таблиц не совпадают с левым столбцом объединения таблиц, будь то использование равенство или неравенство. Мое намерение состоит в том, что это не должно быть равным правым значениям столбца соединения таблицы. Если левый столбец соединения таблицы имеет значение null, я могу вернуть пустые строки в правой таблице, поскольку значение null не равно ничему.
Что я здесь не вижу?
ОСНОВНОЕ РЕДАКТИРОВАНИЕ:
Итак, я добавляю определения таблиц и сценарии. Это не точные сценарии, просто чтобы проиллюстрировать проблему. Я удалил более ранние правки, которые были неправильными, так как ранее их не было в сценарии.
CREATE TABLE dbo.Contact (
ContactID int NOT NULL, --PK
FirstName varchar(10) NULL,
LastName varchar(10) NULL,
StatusID int NULL,
CONSTRAINT PK_Contact_ContactID
PRIMARY KEY CLUSTERED (ContactID)
);
GO
CREATE TABLE dbo.UserGroup (
UserGroupID int NOT NULL, --PK
UserGroup varchar(50) NULL,
StatusID int NULL,
CONSTRAINT PK_UserGroup_UserGroupID
PRIMARY KEY CLUSTERED (UserGroupID)
);
GO
CREATE TABLE dbo.UserGroupContact (
UserGroupID int NOT NULL, --PK,FK
ContactID int NOT NULL, --PK,FK
StatusID int NULL
CONSTRAINT PK_UserGroupContact_UserGroupContactID
PRIMARY KEY CLUSTERED (UserGroupID, ContactID),
CONSTRAINT FK_UserGroupContact_UserGroupId
FOREIGN KEY (UserGroupId)
REFERENCES [dbo].[UserGroup](UserGroupId),
CONSTRAINT FK_UserGroupContact_ContactId
FOREIGN KEY (ContactId)
REFERENCES [dbo].[Contact](ContactId)
);
GO
CREATE TABLE dbo.Account (
AccountID int NOT NULL, --PK
AccountName varchar(50) NULL,
AccountManagerID int NULL, --FK
Balance int NULL,
CONSTRAINT PK_Account_AccountID
PRIMARY KEY CLUSTERED (AccountID),
CONSTRAINT FK_Account_AccountManagerID
FOREIGN KEY (AccountManagerID)
REFERENCES [dbo].[Contact](ContactId),
);
GO
Мой оригинальный запрос будет выглядеть так, как показано ниже. Когда я говорю «левая таблица», я имею в виду таблицу слева от предложения ON в объединении. Если «правильная таблица», то это таблица справа от предложения ON.
SELECT
a.AccountId,
a.AccountName,
a.Balance,
ug.UserGroup,
ugc.UserGroupID,
a.AccountManagerID,
c.FirstName,
c.LastName
FROM dbo.Account a
LEFT JOIN dbo.Contact c
ON a.AccountManagerID = c.ContactID
AND c.StatusID=1
LEFT JOIN dbo.UserGroupContact ugc
ON a.AccountManagerID = ugc.ContactID
AND ugc.StatusID=1
LEFT JOIN dbo.UserGroup ug
ON ugc.UserGroupID = ug.UserGroupID
AND ug.StatusID=1
WHERE
a.Balance > 0
AND ugc.UserGroupID = 10
AND a.AccountManagerID NOT IN (20,30)
Обратите внимание, что в приведенном выше примере сценария первое и второе левые объединения имеют столбец, допускающий значение NULL, в левой таблице и столбец, не имеющий значения NULL, в правой таблице. Третье левое объединение имеет оба столбца, которые можно обнулять в левой и правой таблицах.
Было предложено «перейти к внутреннему соединению или обработать условие NULL в предложении where» или «Возможно использование LEFT JOIN, но в предложении WHERE есть ссылки на ненулевые условия».
В зависимости от намерения предлагается выполнить одно из следующих действий:
a) преобразовать во внутреннее объединение (невозможно, так как я хочу получить несопоставленные строки из таблицы Account)
SELECT
a.AccountId,
a.AccountName,
a.Balance,
ug.UserGroup,
ugc.UserGroupID,
a.AccountManagerID,
c.FirstName,
c.LastName
FROM dbo.Account a
INNER JOIN dbo.Contact c
ON a.AccountManagerID = c.ContactID
AND c.StatusID=1
INNER JOIN dbo.UserGroupContact ugc
ON a.AccountManagerID = ugc.ContactID
AND ugc.StatusID=1
INNER JOIN dbo.UserGroup ug
ON ugc.UserGroupID = ug.UserGroupID
AND ug.StatusID=1
WHERE
a.Balance > 0
AND ugc.UserGroupID = 10
AND a.AccountManagerID NOT IN (20,30)
b) обрабатывать пустые значения в предложении WHERE (невозможно, так как я хочу вернуть строки с нулевыми значениями в столбце a.AccountManagerID и в ugc.UserGroupID)
SELECT
a.AccountId,
a.AccountName,
a.Balance,
ug.UserGroup,
ugc.UserGroupID,
a.AccountManagerID,
c.FirstName,
c.LastName
FROM dbo.Account a
LEFT JOIN dbo.Contact c
ON a.AccountManagerID = c.ContactID
AND c.StatusID=1
LEFT JOIN dbo.UserGroupContact ugc
ON a.AccountManagerID = ugc.ContactID
AND ugc.StatusID=1
LEFT JOIN dbo.UserGroup ug
ON ugc.UserGroupID = ug.UserGroupID
AND ug.StatusID=1
WHERE
a.Balance > 0
AND ugc.UserGroupID = 10
AND a.AccountManagerID NOT IN (20,30)
AND a.AccountManagerID IS NOT NULL
AND ugc.UserGroupID IS NOT NULL
c) обрабатывать пустые значения в предложении ON (я остановился на этом, что, как мне показалось, не имеет смысла, потому что это избыточно)
SELECT
a.AccountId,
a.AccountName,
a.Balance,
ug.UserGroup,
ugc.UserGroupID,
a.AccountManagerID,
c.FirstName,
c.LastName
FROM dbo.Account a
LEFT JOIN dbo.Contact c
ON a.AccountManagerID = c.ContactID
AND c.StatusID=1
AND a.AccountManagerID IS NOT NULL
LEFT JOIN dbo.UserGroupContact ugc
ON a.AccountManagerID = ugc.ContactID
AND ugc.StatusID=1
AND a.AccountManagerID IS NOT NULL
LEFT JOIN dbo.UserGroup ug
ON ugc.UserGroupID = ug.UserGroupID
AND ug.StatusID=1
AND ugc.UserGroupID IS NOT NULL
WHERE
a.Balance > 0
AND ugc.UserGroupID = 10
AND a.AccountManagerID NOT IN (20,30)
Я не привел пример для ISNULL (). Кроме того, я думаю, что он не имел в виду неявные внутренние объединения.
Напомним, как мне справиться с этим предложением: «Существует LEFT JOIN, но есть ненулевые условия, на которые есть ссылка в предложении WHERE.»? Он прокомментировал, что это «сомнительная логика левого соединения».