Sapforum.Biz
Инструменты => ABAP - Инструментальные средства => Тема начата: A. от Сентябрь 24, 2012, 04:18:22 pm
-
Добрый день.
Есть сложный SELECT, который содержит множество JOIN-ов - как INNER, так и OUTER. Структура у него следующая:
SELECT DISTINCT <поля для выбора>
APPENDING CORRESPONDING FIELDS OF TABLE gt_itab
FROM table_1
INNER JOIN table_2 ON
table_1~field_1 = table_2~field_1 AND
table_1~field_2 = table_2~field_2
INNER JOIN table_3 ON
table_1~field_1 = table_3~field_1 AND
table_1~field_2 = table_3~field_2 AND
table_1~field_3 = table_3~field_3
INNER JOIN table_4 ON
table_1~field_5 = table_4~field_5
LEFT OUTER JOIN table_5 ON
table_1~field_6 = table_5~field_6
LEFT OUTER JOIN table_6 ON
table_1~field_7 = table_6~field_7
LEFT OUTER JOIN table_7 ON
table_1~field_8 = table_7~field_8 AND
table_1~field_9 = table_7~field_9
WHERE table_5~field_10 = 'ABC'
AND table_5~field_11 >= 'DEF'
AND table_3~field_1 IN so_fld_1
AND table_3~field_2 IN so_fld_2
AND table_1~field_12 IN so_fld_12
AND table_1~field_13 IN so_fld_13.
Если в SE11 задать для table_1 критерии, указанные в условии WHERE, то не выбирается никаких данных. Однако, в результирующей внутренней таблице заполняются поля из этой таблицы! Как так происходит? Условие отбрасывается из-за наличия LEFT JOIN-а? Какие действия нужно выполнить с помощью SE11, чтобы выйти на те значения, что получаются во внутренней таблице?
-
Дополнение: по условиям в WHERE для таблиц table_3 и table_5 данные выбираются. Но связывание всех таблиц в этом SELECT-е производится по таблице table_1.
-
Вообще, как работают JOIN-ы? Сначала данные выбираются из всех таблиц, связываются и фильтруются? Или как-то иначе?
-
Вообще, как работают JOIN-ы?
Чуть позже отпишусь.
-
Было бы неплохо, т.к. осмотр плана запроса ясности не внёс.
-
Значит так, для начала кто есть кто из команд. Как я понимаю с точки зрения OpenSQL:
INNER JOIN = JOIN
LEFT OUTER JOIN = LEFT JOIN
т.е. INNER и OUTER можно в принципе не использовать, так как просто JOIN это всегда INNER, а LEFT JOIN это всегда LEFT OUTER JOIN.
Далее так для справки, в соединении можно использовать до 25 таблиц, точнее одна таблица основная после FROM и к ней можно логически присоединить еще 24 таблицы.
Теперь как вся эта кухня работает, опять же только мои мысли, если что-то скажу не так, ну значит ошибся. И так имеем соединение таблиц, используя команду JOIN (от же INNER JOIN), система, выполняет по заданному условию JOIN <…> ON <…>, объединение двух таблиц. При этом, если для какой-то из записей при объединения нет соответствия в соседней таблице, то такие записи удаляются, т.е. считается что объединение не произошло, т.е например есть две таблицы со следующими записями:
Пример объединения таблиц по полям WERKS и LGORT
Таблица: TABLE_ONE (Поля в таблице: WERKS. LGORT, TEXT)
1000 0001 Test
1000 0002 Test
1000 0003 Test
1000 0004 Test
1000 0005 Test
Таблица: TABLE_TWO (Поля в таблице: WERKS. LGORT, TEXT)
1000 0002 Test
1000 0005 Test
1000 0007 Test
Система выполнит объединение и получит сначала следующую таблицу
1. 1000 0001 Test
2. 1000 0002 Test = 1000 0002 Test
3. 1000 0003 Test
4. 1000 0004 Test
5. 1000 0005 Test = 1000 0005 Test
6. = 1000 0007 Test
Теперь произойдет удаление записей 1, 3, 5 и 6 так как для этих записей нет соответствия друг другу, а после этого выполнится применение условия отбора для записей 2 и 5 по условию указанному после WHERE соответственно задав, например склад TABLE_TWO~LGORT = «0005» записи будут выбраны, точнее будет выбрана одна запись 5. Для склада 0004 соответственно система скажет, что записей в выборе нет.
Теперь сделаем объединение таблиц, используя соединение LEFT JOIN (оно же LEFT OUTER JOIN). Произойдет такое же объединение таблиц? как и случае с INNER, но после объединения будут удалены только записи таблицы TABLE_TWO, которые не имеют соответствия в таблице TABLE_ONE, т.е. результирующий набор будет иметь в своем составе записи с 1 по 5, после чего на эту таблицу будет наложено условие, заданное в WHERE, т.е. соответственно если ограничение будет по складу TABLE_TWO~LGORT = «0005», то будет выбрана одна запись, а если там будет задан склад «0007», то соответственно ничего не будет выбрано, так как записи с таким складом после выполнения объединения в полученном наборе не будет.
Вывод раз: Сначала идет объединения таблиц указанных в запросе и только потом на результирующий набор накладывается условие WHERE. Объединение идет согласно заданным правилам т.е. или INNER или LEFT.
Вывод два: Так как OpenSQL это не совсем те SQL-ли которые есть в разных базах, т.е. это какое-то среднее звено, со своими ограничениями, т.е. например нельзя в ограничениях WHERE указать значения по таблице которая соединяется через LEFT JOIN, ну по крайней мере у меня говорит что: No fields from the right-hand table of a LEFT OUTER JOIN may appear in the WHERE condition: "FOUR~LGORT", т.е. таблица которая соединена через LEFT не разрешает использовать свои поля в условии отбора WHERE, поэтому как у вас получилось задать для LEFT OUTER JOIN table_5 использовать поля пятой таблицы в WHERE table_5~field_10 = 'ABC' у меня так не выходило ограничивать объединение.
PS: Ну типа такие мысли. Если кто может поправить, пишем…
-
Вот полный код запроса:
SELECT DISTINCT
tab_1~fld_1 tab_1~fld_2 tab_1~fld_3 tab_1~fld_4 tab_1~fld_5 tab_1~fld_6 tab_1~fld_7 tab_1~fld_8 tab_1~fld_9 tab_1~fld_10 tab_1~fld_11 tab_1~fld_12 tab_1~fld_13 tab_1~fld_14 tab_1~fld_15 tab_1~fld_16 tab_1~fld_17
tab_2~fld_18 tab_2~fld_19 tab_2~fld_20 tab_2~fld_21 tab_2~fld_22 tab_2~fld_23 tab_2~fld_24 tab_2~fld_25
tab_3~fld_26 tab_3~fld_27 tab_3~fld_28 tab_3~fld_29 tab_3~fld_30 tab_3~fld_31 tab_3~fld_29
tab_4~fld_32 tab_4~fld_33 tab_4~fld_34 tab_4~fld_35
tab_5~fld_28 tab_5~fld_36 tab_1~fld_37
tab_6~fld_38
tab_7~fld_39 tab_7~fld_40
tab_8~fld_41 tab_8~fld_42 tab_8~fld_43 tab_8~fld_44
tab_9~fld_45 tab_9~fld_46 tab_9~fld_47 tab_9~fld_48 tab_9~fld_49 tab_9~fld_50 tab_9~fld_51 tab_9~fld_52 tab_9~fld_53
APPENDING CORRESPONDING FIELDS OF TABLE gt_itab
FROM tab_1
INNER JOIN tab_2 ON
tab_1~fld_1 = tab_2~fld_1 AND
tab_1~fld_2 = tab_2~fld_2 AND
tab_1~fld_3 = tab_2~fld_3 AND
tab_1~fld_4 = tab_2~fld_4
INNER JOIN tab_3 ON
tab_1~fld_1 = tab_3~fld_1 AND
tab_1~fld_2 = tab_3~fld_2 AND
tab_1~fld_3 = tab_3~fld_3
INNER JOIN tab_4 ON
tab_1~fld_55 = tab_4~fld_55
INNER JOIN tab_5 ON
tab_1~fld_8 = tab_5~fld_56
LEFT OUTER JOIN tab_6 ON
tab_1~fld_37 = tab_6~fld_37
LEFT OUTER JOIN tab_7 ON
tab_1~fld_14 = tab_7~fld_14
LEFT OUTER JOIN tab_8 ON
tab_1~fld_55 = tab_8~fld_55 AND
tab_1~fld_17 = tab_8~fld_17
LEFT OUTER JOIN tab_9 ON
tab_1~fld_1 = tab_9~fld_1 AND
tab_1~fld_2 = tab_9~fld_2 AND
tab_1~fld_3 = tab_9~fld_3
WHERE tab_5~fld_40 = 'R'
AND tab_5~fld_58 >= sy-datum
AND tab_3~fld_1 IN s_fld_1
AND tab_3~fld_2 IN s_fld_2
AND tab_3~fld_26 IN s_fld_26
AND tab_1~fld_6 IN so_fld_6
AND tab_1~fld_8 IN s_fld_8
AND tab_1~fld_37 IN s_fld_37
AND tab_4~fld_55 IN s_fld_55.
Про то, что нельзя использовать поля правой таблицы при соединении LEFT, я в курсе, просто на скорую руку склепал запрос.
Про то, как соединяются две таблицы, понятно. А когда таблиц 9, как в моём случае, в какой последовательности идет выбор данных и последующие их соединения и фильтрация? Я посмотрел план запроса, сначала идет выбор из tab_2, потом tab_1, затем tab_9, и т.д. Логика неясна. В другой системе с этим же запросом план показывает сначала tab_3, tab_1, tab_9, и т.д. - то есть по-другому.
-
Про то, как соединяются две таблицы, понятно. А когда таблиц 9, как в моём случае, в какой последовательности идет выбор данных и последующие их соединения и фильтрация? Я посмотрел план запроса, сначала идет выбор из tab_2, потом tab_1, затем tab_9, и т.д. Логика неясна. В другой системе с этим же запросом план показывает сначала tab_3, tab_1, tab_9, и т.д. - то есть по-другому.
Ну тут как бы ситуация тоже ясна, во-первых, с точки зрения работы без оптимизации понятно, что мы соединяем все таблицы по INNER не важно в каком прядке, главное потом то, что останутся записи присутствующие во всех объединенных таблицах, но так как у нас есть оптимизатор, то по бытовой логике я бы читал сначала таблицы с лучшей статистикой и меньшим объемом данных, потому что если имеем два таблицы в которых в одной 100 записей, а в другой 10, то я бы прочитал сначала ту в которой 10 и уже ее бы соединял бы с большей таблицей, так как в этом случае мне бы пришлось по максимуму из второй таблицы тоже прочитать всего 10 записей а не все 100, по полям объединения. Поэтому тут как говорится оптимизатору виднее, в каком порядке требуется читать данные из таблиц в условии INNER. Ну а с таблицами соединенными по LEFT опять же оптимизатор сам тоже решает в какой момент и какую из них подгрузить для результирующей выборки. Вообще я не знаю что за база у вас лежит внизу SAP.
-
Если предположить, что сначала формируется результат работы всех INNER JOIN, то что будет, если к этому результату будет добавлена таблица с условием LEFT JOIN? Выберутся все записи из таблицы справа от LEFT JOIN (см. SE38, DEMO_JOINS, "demo2 OUTER JOIN demo1")?
Потом, конкретно в моём случае, в SE11 по условию в WHERE из таблицы tab_1 не было выбрано ни одной записи, однако же в результирующей внутренней таблице gt_itab содержатся данные из соответствующих полей этой таблицы! Как так? Какая логика в работе?
P.S. БД - Оракл.
-
Если предположить, что сначала формируется результат работы всех INNER JOIN, то что будет, если к этому результату будет добавлена таблица с условием LEFT JOIN? Выберутся все записи из таблицы справа от LEFT JOIN (см. SE38, DEMO_JOINS, "demo2 OUTER JOIN demo1")?
Потом, конкретно в моём случае, в SE11 по условию в WHERE из таблицы tab_1 не было выбрано ни одной записи, однако же в результирующей внутренней таблице gt_itab содержатся данные из соответствующих полей этой таблицы! Как так? Какая логика в работе?
Ну из плана запроса,таблица 9 у вас выбирается третьей, значит оно все таки по каким-то своим условиям и правилам объединяет таблицу 2 или 3 с таблицей 1, а потом к этому результату доопределяет данные таблицы 9. Вообще-то там можно использовать скобки как я понимаю для определения порядка объединения таблиц. А далее еще надо похоже читать как оракловая база работает с соединениями таблиц. Я так понял таблицы у вас для примера приведены, т.е. реальный запрос немного другой, так что проверить его на моих данных и базе DB6 не получится. Вообще-то я в кодах системы сложные объединения не встречал практически, сам обычно более чем основная таблица + пяток вспомогательных справочных не объединял.
PS: Кстати где почитать как система работает с базой данных и как это передается на уровень базы с уровня SAP ABAP-а, не подскажу, я статьи на такие темы не встречал к сожалению :-\
-
Да вот я думаю, что не должно быть так, что результат работы селекта должен зависеть от типа БД и её оптимизатора. План запроса я посмотрел, дабы он как-то улёгся в логическую картину работы селекта, описанную в хелпе. Не улёгся.
Тут вопрос ещё такой возникает. Допустим, всю эту басню я хочу сделать отдельными SELECT во внутренние таблицы, а потом соединять их. Но! Если идти по порядку, и выбрать данные из tab_1, которых там нет по условию в WHERE, то к чему потом подклеивать остальные? Ни к чему, выходит. Тогда нужно брать другие таблицы, смотреть, есть ли в них данные по условиям в WHERE, и потом делать как бы наоборот - не от tab_1 плясать, когда её значения являются ключами для выбора из остальных таблиц, а значения в остальных таблицах являются ключами для выбора из tab_1.
Вот такие у меня нечётко пока оформившиеся размышления. Есть еще мысль про подобие пустой таблицы для FOR ALL ENTRIES, когда выбирается всё.
-
Да вот я думаю, что не должно быть так, что результат работы селекта должен зависеть от типа БД и её оптимизатора.
Вот тут как раз есть варианты... так как SQL-база она у всех SQL-база в принципе, а вот дальше идут разночтения именно в оптимизаторах и то как они работают с таблицами. К примеру статистика индекса слетела или стала хуже и все, запрос который работал секунды, стал тупить по часу. И это только статистика индекса, которую в плане запроса сразу видно :-\
-
Вот такие у меня нечётко пока оформившиеся размышления. Есть еще мысль про подобие пустой таблицы для FOR ALL ENTRIES, когда выбирается всё.
Ну надеюсь как размышления дойдут до логического конца, напишешь о результатах 8)
-
Ну, если я додумаюсь, то непременно поделюсь.
Во всех курсах пишут, что Open SQL используется специально, чтобы абстрагироваться от технической реализации соответствующей БД с помощью DBMS. Поэтому по идее, основываясь на этой информации, ни тип БД, ни что иное влиять не должны на логику работы SELECT-а в программе.
-
Во всех курсах пишут, что Open SQL используется специально, чтобы абстрагироваться от технической реализации соответствующей БД с помощью DBMS. Поэтому по идее, основываясь на этой информации, ни тип БД, ни что иное влиять не должны на логику работы SELECT-а в программе.
Ну, мне кажется, не путаем диалекты, т.е. конструкции языка, которые действительно не должны влиять от варианта используемой БД с техникой выбора данных, т.е. работой оптимизатора, который как раз зависит от БД, т..е. конструкция объединения, не зависит, а вот как работает само объединение таблиц, очень может быть, что могут быть варианты. И еще раз повторюсь, в программах SAP, я сложных запросов не встречал это что-то типа:
SELECT * FROM equi
INTO CORRESPONDING FIELDS OF TABLE lt_v_equi_iflos
FOR ALL ENTRIES IN equnr
WHERE equnr = equnr-low
AND erdat IN erdat
AND ernam IN ernam
AND aedat IN aedat
AND aenam IN aenam
AND begru IN begru
AND eqtyp IN eqtyp
AND eqart IN eqart
AND ansdt IN ansdt
AND answt IN answt
AND waers IN waers
AND elief IN elief
AND herst IN herst
AND serge IN serge
AND typbz IN typbz
AND krfkz LIKE krfkz
AND kmatn IN kmatn
AND matnr IN matnr
AND sernr IN sernr
AND charge IN charge
AND kunde IN kunde
AND herld IN herld
AND baujj IN baujj
AND invnr IN invnr
AND groes IN groes
AND brgew IN brgew
AND gewei IN gewei
AND cuobj IN r_cuobj
AND auldt IN auldt
AND inbdt IN inbdt
AND werk IN werk
AND lager IN lager
AND uii IN gr_uii
AND (gt_where) .
где выборка идет по ракурсу БД, типа как на рисунке ниже. В самих программах, что-то типа проведенного запроса, не встречалось.
-
Всем добрый вечер.
Подскажите, пожалуйста, по такому вопросу.
Есть выборка:
select {поля таблицы 1}+{поле keyz1_k таблицы 2}
into corresponding fields of table lt_tab
from Таблица 1 as z
left join Таблица 2 as t
on z~keyz1 eq t~keyz1_k
where z~budat in gr_date
and z~bukrs eq p_bukrs.
Есть другая выборка:
select {поля таблицы 1}
into corresponding fields of table lt_tab_tmp
from Таблица_1
where budat in gr_date and
bukrs eq p_bukrs.
Как мне казалось, количество строк во внутренних таблицах lt_tab и lt_tab_tmp должно быть одинаково. Однако практика показывает иное.
Как я думал, при левом соединении сначала выбираются записи из основной таблицы (той, что слева от оператора LEFT), а затем к ним пристыковываются данные из второй таблицы (той, что справа), т.е. заполняются поля результирующей таблицы, если есть соответствующие данные. Но всё почему-то не так. Количество записей в каждой из выборок различается.
Согласно плану запроса, сначала выбираются данные из Таблицы 2, потом из Таблицы 1, а потом выполняется операция HASH JOIN RIGHT OUTER, и последней - операция FILTER (см. аттач).
Как это можно объяснить работу LEFT OUTER JOIN?
-
Вообще, для понимания хотелось бы представить первую выборку в виде двух запросов, которые дадут такой же результат.
-
Дополнительная информация: в Таблица 2 содержится 190.434 записей. На скриншоте же видно, что выбирается 172.040 записей. Согласно чему идет ограничение?
Далее - в Таблица 1 по условию в where содержится 78.542 записей, именно столько же и выбирается второй выборкой. Первой же выборкой получается 78.950 записей - плюс 408 записей.
-
Поле keyz1_k Таблицы 2 не ключевое. Кажется, дело в том, что из первой таблицы "плывут" дубликаты, т.к. полей keyz1_k - не ключевое, и записей с одним и тем же значением может быть несколько, к которым "пристыковываются" записи из таблицы слева от LEFT. Т.к. внутренняя таблица, куда укладываются данные, объявлена как сортированная с НЕ уникальным ключом, то фокус проходит.
В общем, в первой выборке надо DISTINCT использовать, тогда количество выбираемых записей совпадает со второй выборкой.
:)
-
В общем, в первой выборке надо DISTINCT использовать, тогда количество выбираемых записей совпадает со второй выборкой.
:)
Тихо сам с собою...
В чем был смысл поста "подскажите, пожалуйста, по такому вопросу."?
Помочь разобраться, почему left join возвращает больше записей, чем отдельный select?
Это просто: если в таблице 2 поле keyz1_k содержит неуникальные значения, то в результирующей таблице будут записи с одинаковыми полями из таблицы 1.
Но вот специально делать секрет о именах таблиц как то не способствует разбирательству. :-\
-
Но вот специально делать секрет о именах таблиц как то не способствует разбирательству. :-\
Да и не ясно что в этих именах таблиц такого секретного...
-
если в таблице 2 поле keyz1_k содержит неуникальные значения, то в результирующей таблице будут записи с одинаковыми полями из таблицы 1.
Простите как бэ, я как бэ ужэ разобрался, я всегда так делаю.
Спосибо за помосчь.
-
Да и не ясно что в этих именах таблиц такого секретного...
Не вижу причин, по которым имена таблиц дали бы больше ясности. В данном случае там Z.
-
Простите как бэ, я как бэ ужэ разобрался, я всегда так делаю.
Да нормально... зато другим будет пример...
-
В общем подсказали тут как эта кухня работает:
http://ru.wikipedia.org/wiki/Join_(SQL)
LEFT OUTER JOINОператор левого внешнего соединения LEFT OUTER JOIN соединяет две таблицы. Порядок таблиц для оператора важен, поскольку оператор не является симметричным.
Заголовок таблицы-результата является объединением (конкатенацией) заголовков соединяемых таблиц.
Тело результата логически формируется следующим образом. Пусть выполняется соединение левой и правой таблиц по предикату (условию) p.
1.В результат включается внутреннее соединение (INNER JOIN) левой и правой таблиц по предикату p.
2.Затем в результат добавляются те записи левой таблицы, которые не вошли во внутреннее соединение на шаге 1. Для таких записей поля, соответствующие правой таблице, заполняются значениями NULL.
так что думаю, теперь как бы понятно, почему количество записей не совпадает.