Объединение данных из двух таблиц в Oracle с помощью INSTR - PullRequest
0 голосов
/ 14 сентября 2018

У меня есть 2 таблицы TAB_A и TAB_B.Я хочу написать запрос, где TAB_A является таблицей управления (по существу, TAB_A будет на левой стороне в левом внешнем соединении).Я должен присоединиться, используя столбцы A1 и A2 от TAB_A и B1 от TAB_B.B1 будет иметь сцепление A1 и A2 вместе с другими символами в том же столбце.

Я пробовал что-то вроде ниже:

SELECT A.*, B.B3
FROM TAB_A A LEFT OUTER JOIN TAB_B B
ON INSTR(B.B1, A.A1||'-'||A.A2) > 0;

Однако этот запрос выполняется вечно.Обратите внимание, что это БД Oracle.Любая помощь будет высоко оценена.A1 || '-' || A2 может присутствовать где угодно в B1.

e.g. A1 = X103
A2 = VN12345
B1 = 1w466X103-VN12345HG0034

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Согласно моему пониманию в TAB_A столбец A1 может находиться в левой части строки перед - в столбце B1 из таблицы TAB_B и столбце A2 из таблицы TAB_A canнаходиться в оставшейся половине строки столбца B1 таблицы TAB_B.

Результат запроса будет ниже.

select * from TAB_A A left outer join TAB_B B on substr(B.B1,1,instr(B.B1,'-')-1) like '%'||A.A1||'%' and substr(B.B1,instr(B.B1,'-')+1) like '%'||A.A2||'%';

0 голосов
/ 14 сентября 2018

Это ответ, почему утверждение продолжается вечно .

Если вы исследуете план выполнения, вы видите что-то вроде этого

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |   500 | 45000 |   113   (0)| 00:00:02 |
|   1 |  NESTED LOOPS OUTER|       |   500 | 45000 |   113   (0)| 00:00:02 |
|   2 |   TABLE ACCESS FULL| TAB_A |   100 |  4400 |     3   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| TAB_B |     5 |   230 |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter(INSTR("B"."B1"(+),"A"."A1"||'-'||"A"."A2")>0)

Таким образом, вы FULL SCAN таблица TAB_A и для каждой строки это вы FULL SCAN таблица TAB_B.

Технически, вы вычисляете декартово объединение двух таблиц (содержащих строки count (TAB_A) * count (TAB_B)) и затем фильтруете совпадения.

Кстати, никакая переформулировка предиката (с LIKE и т. Д.) Не изменит это поведение - это изменение только для предиката FILTER.

Единственное, что мне приходит на ум, вы можете сделать - если вам повезет, и TAB_B содержит много строк без знака минус , чтобы отфильтровать их, так как эти строки по определению могут не сопоставьте и создайте временную таблицу меньшего размера, которая используется в объединении.

create table tab_b_tmp as
select * from tab_b
where b1 like '%-%' /* eliminate all rows that can't match */
;

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

Удачи!

...