2015-07-28 3 views
3
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Atbl') 
DROP TABLE Atbl 

CREATE TABLE ATbl 
(
    Id int unique, 
    AName varchar(20), 
) 

GO 

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Btbl') 
    DROP TABLE Btbl 

CREATE TABLE BTbl 
(
    Id int unique, 
    BName varchar(20), 
    ATblId int 
) 

GO 

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Ctbl') 
    DROP TABLE Ctbl 

CREATE TABLE CTbl 
(
    Id int unique, 
    CName varchar(20), 
    BTblId int 
) 

GO 

TRUNCATE TABLE Atbl 
TRUNCATE TABLE Btbl 
TRUNCATE TABLE Ctbl 


INSERT INTO Atbl VALUES (1, 'Name1') 
INSERT INTO Atbl VALUES (2, 'Name2') 
INSERT INTO Atbl VALUES (3, 'Name3') 

INSERT INTO Btbl VALUES (1, 'Name1', 2) 
INSERT INTO Btbl VALUES (2, 'Name2', 3) 

INSERT INTO Ctbl VALUES (1, 'Name2', 2) 

select * from atbl 
left join btbl on btbl.atblid=atbl.id 
inner join ctbl on ctbl.btblid=btbl.id 

select * from atbl 
left join 
(select btbl.id, btbl.atblid from btbl 
inner join ctbl on ctbl.btblid=btbl.id) a 
on atbl.id=a.atblid 

Sql results for both queriesПочему левое соединение превращается во внутреннее соединение, если внутреннее соединение включено в запрос?

Почему один внутреннее соединение в запросе превращает все запросы в внутреннее соединение. Первый запрос соединяется с TblA - (LEFT JOIN) -> TblB -> (INNER JOIN) -> TblC = Весь запрос соединен внутри.

Единственное решение, которое я нашел, это присоединение к подзапросу в левом соединении, однако я не понимаю, как оно отличается.

ответ

2

Это обычное поведение в реализации баз данных из-за последствий вложения вложения. Этот результат будет иметь ряд левых объединений, за которыми следует внутреннее соединение (или CROSS APPLY вместо OUTER APPLY).

Чтобы избежать этого, вы уже попали на решение:

select * from atbl 
left join 
    (select btbl.id, btbl.atblid 
     from btbl 
     inner join ctbl on ctbl.btblid=btbl.id) a 
     on atbl.id=a.atblid 

Это не-коррелированных подзапросов, как вы не ссылается ATBL в скобках - это означает, двигатель может выбрать достаточно хорошая стратегия объединения для него или вычислять весь подзапрос один раз, а не ряд за строкой.

Другого варианта изменить все таблицы присоединяются слева присоединяется:

select * from atbl 
    left join btbl on btbl.atblid=atbl.id 
     left join ctbl on ctbl.btblid=btbl.id 
WHERE 
    -- Rows where the first LEFT is not satisfied, or BOTH are satisfied. 
    (btbl.atblid IS NULL OR ctbl.btblid IS NOT NULL) 

Вы можете использовать ИНЕК для фильтрации, где либо ни один из стыков с B вперед были поражена (т.е. либо я Жду» t найти B или я нашел как aa B, так и C).

0

С первым запросом первое соединение происходит первым, а результат выполняется внутренним соединением со следующей таблицей (ctbl).

Где, как и во втором запросе, первое соединение происходит первым, а результат остается соединенным с вашей первой таблицей (atbl). Надеюсь, это ответ

+0

ОК. если первое соединение произошло первым, оно все равно должно показать все результаты от TblA. И вообще, что лучше включить весь запрос в левые соединения или сделать подзапрос, как второй? – schizofreindly

+0

Нет, как только левое соединение происходит, результат берется как одна новая таблица. Эта таблица выполняется внутренним соединением с третьей таблицей. Таким образом, итоговыми значениями будут те, которые соответствуют результирующим значениям вашего левого соединения и третьей таблицы. –

0

У вас все еще есть LEFT JOIN, но вы делаете INNER JOIN на ctbl, который отфильтровывает все данные. Глядя на ваше заявление я думаю, что вы ищете NESTED INNER JOIN в LEFT JOIN:

SELECT * 
FROM atbl 
     LEFT JOIN btbl 
      INNER JOIN ctbl 
       ON ctbl.btblid=btbl.id 
      ON btbl.atblid=atbl.id 

Таким образом, вы делаете LEFT JOIN между atbl и [INNER JOIN между btbl и ctbl]. Обратите внимание, что условие между atbl и btbl является последним, и я специально идентифицировал INNER JOIN немного больше, чтобы сделать его более очевидным, что он НЕИСПРАВЛЯЕТ.

Надеюсь, это поможет.

Смежные вопросы