Я нашел то, что, по моему мнению, является ошибкой в Oracle, но мне интересно, есть ли что-то задокументированное, что я пропустил.
скрипки: Oracle: http://sqlfiddle.com/#!4/43c19/2 SQL Server: http://sqlfiddle.com/#!3/ddc49/1 MySql: http://sqlfiddle.com/#!2/43c195/1
В основном у меня есть основная таблица, в которой я оставил присоединение к вторичной таблице. Затем я оставил соединение на виду. Если я укажу в соединении с представлением, что только хочу присоединиться, когда столбец во вторичной таблице не равен нулю, я получаю неожиданные результаты. Это лучше всего объяснить, показывая запрос:
SELECT
1,
MainTable.*
FROM
MainTable
LEFT JOIN SecondaryTable ON MainTable.KeyColumn = SecondaryTable.KeyColumn
LEFT JOIN ViewWithoutSecondary ON ((SecondaryTable.KeyColumn IS NOT NULL) AND SecondaryTable.KeyColumn = ViewWithoutSecondary.KeyColumn)
UNION ALL
SELECT
2,
MainTable.*
FROM
MainTable
LEFT JOIN SecondaryTable ON MainTable.KeyColumn = SecondaryTable.KeyColumn
LEFT JOIN ViewWithSecondary ON ((SecondaryTable.KeyColumn IS NOT NULL) AND SecondaryTable.KeyColumn = ViewWithSecondary.KeyColumn)
См. ниже сценарии создания, чтобы проверить его самостоятельно. В SQL Server и MySql я получаю те же результаты, однако Oracle отличается. В схеме есть три таблицы и два вида. Представления определяются следующим образом:
CREATE VIEW ViewWithoutSecondary
AS
SELECT
TertiaryTable.KeyColumn,
TertiaryValue + 1 ViewValue
FROM
TertiaryTable
CREATE VIEW ViewWithSecondary
AS
SELECT
SecondaryTable.KeyColumn,
TertiaryValue + 1 ViewValue
FROM
SecondaryTable
LEFT JOIN TertiaryTable ON SecondaryTable.KeyColumn = TertiaryTable.KeyColumn;
В Oracle я обнаружил, что если представление содержит ссылку на SecondaryTable, тогда я получаю только строки из MainTable, которые имеют совпадение в Secondary table. Мне кажется, что Oracle каким-то образом вставляет код представления, так что одна из строк опускается.
Я думаю, что если MainTable имеет три строки, то выполнение двух левых объединений должно всегда возвращать три строки по крайней мере плюс любые результаты из соединения. Однако в приведенном примере это не так.
Я знаю, что SecondaryTable.KeyValue IS NOT NULL
избыточно, поскольку вторая половина предложения не будет истинна, если значение равно null, но я пытаюсь переработать запрос, чтобы помочь оптимизатору разработать лучший план.
Полное создание script для запуска примера:
CREATE TABLE MainTable
(
KeyColumn varchar(32),
ValueColumn varchar(32)
);
INSERT INTO MainTable VALUES ('123', 'abc');
INSERT INTO MainTable VALUES ('456', 'def');
INSERT INTO MainTable VALUES ('789', 'ghi');
CREATE TABLE SecondaryTable
(
KeyColumn varchar(32),
SecondaryValue integer
);
INSERT INTO SecondaryTable VALUES ('123', 1);
INSERT INTO SecondaryTable VALUES ('456', 2);
CREATE TABLE TertiaryTable
(
KeyColumn varchar(32),
TertiaryValue integer
);
INSERT INTO TertiaryTable VALUES ('123', 1);
CREATE VIEW ViewWithoutSecondary
AS
SELECT
TertiaryTable.KeyColumn,
TertiaryValue + 1 ViewValue
FROM
TertiaryTable;
CREATE VIEW ViewWithSecondary
AS
SELECT
SecondaryTable.KeyColumn,
TertiaryValue + 1 ViewValue
FROM
SecondaryTable
LEFT JOIN TertiaryTable ON SecondaryTable.KeyColumn = TertiaryTable.KeyColumn;