#sql #sql-server #join
#sql #sql-сервер #Присоединиться
Вопрос:
У меня есть следующий запрос:
SELECT c.cardNo, acc.accountId
FROM card c
LEFT JOIN accounts acc ON c.accId = acc.id
Приведенный выше запрос возвращает 500 строк. В приведенном выше запросе я извлекаю все карточки. Я притворяюсь, что вижу, что карточки, у которых нет учетной записи (просто в качестве примера), вернут NULL вместо AccountId.
Затем я хотел получить все карточки и только идентификатор учетной записи стран, зарегистрированных в Европе. Итак, я все еще хотел 500 карточек, поэтому я попробовал следующее:
SELECT c.cardNo, acc.accountId
FROM card c
LEFT JOIN accounts acc ON c.accId = acc.id AND acc.registrationContinent = 'EU'
Тем не менее, к моему удивлению, я получаю 300 строк (а не 500), приведенное выше также эквивалентно, как если бы у меня было предложение WHERE.
Кто-нибудь может любезно объяснить, почему левое соединение возвращает не все записи из таблицы card?
Комментарии:
1. Все ли 500 карточек имеют континент регистрации как «EU»
2.Если вы просто выполните
SELECT * FROM card
, сколько строк вы получите? Несмотря на название, возможно ли, чтобы в было несколькоaccounts
строк, которые имеют одинаковоеid
значение?3. Можете ли вы jst увидеть отдельный registration_continent из приведенного выше запроса..
4. И нет, это не похоже на предложение where . Если вы добавите
acc.registrationContinent = 'EU'
в предложение where, вы не получите карточки без учетной записи. В то время как ваш второй запрос также выдает эти результаты.
Ответ №1:
Вы указали условие в соединении, теперь это будет частью того, как таблицы сопоставляются друг с другом. Чтобы получить желаемые результаты, вы можете использовать подзапрос для фильтрации результатов, которые вы присоединяете к своим картам. Вот так:
SELECT c.cardNo,
acc.accountId
FROM card c
LEFT JOIN (
SELECT accountId
FROM accounts
WHERE registrationContinent = 'EU'
) acc
ON c.accId = acc.id
Ответ №2:
потому что вы фильтруете учетные записи, которые не находятся в ‘EU’.
Если вам нужно нулевое значение в acc.accountid, когда account.registrationContinent отсутствует EU
, вы можете сделать
SELECT c.cardNo,
case when acc.registrationContinent = 'EU' then acc.accountId else NULL end
FROM card c
LEFT JOIN accounts acc ON c.accId = acc.id
Но я думаю, что у вас много учетных записей по карточкам, некоторые с EU, некоторые без EU.
Итак, с вашим вторым запросом у вас все еще есть все ваши карты (могу поспорить, что у вас менее 500 разных карт и, вероятно, менее 300 разных карт).
Первый запрос будет возвращать несколько раз одну и ту же карточку, если у нее более одной учетной записи (каждый раз с другой учетной записью).
Просто проверьте
select count(*) from card
чтобы посмотреть, сколько у вас разных карточек.
Ответ №3:
Когда у вас есть условие в инструкции join, фильтруются первые данные, затем происходит объединение. Когда вы указываете условие в WHERE, сначала происходит соединение, затем данные фильтруются.
Приведенный ниже пример может вам помочь..
DECLARE @A TABLE (ID INT, NAME VARCHAR(5), DEPID INT)
DECLARE @B TABLE (DEPID INT, DEPNAME VARCHAR(5),COUNTRY VARCHAR(5))
INSERT INTO @A VALUES (1,'JIT',101),(2,'PAT',101),(3,'JOM',101),(4,'MARK',102),(5,'FAL',103)
INSERT INTO @B VALUES (101,'HR','IND'),(102,'ACC','IND'),(103,'OPER','US')
SELECT * FROM @A
SELECT * FROM @B
Результат
SELECT *
FROM @A A
LEFT JOIN @B B ON A.DEPID = B.DEPID
SELECT *
FROM @A A
LEFT JOIN @B B ON A.DEPID = B.DEPID AND B.COUNTRY = 'US'
Результат