Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 что лучше использовать join или (+)  [new]
26IVC
Member

Откуда:
Сообщений: 49
Использую join, говорят что он из MSSQL, что мне обязательно переходить на синтаксис (+)?
8 авг 07, 10:59    [4494703]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
tru55
Member

Откуда: СПб
Сообщений: 19790
не обязательно, только в 8 join-а не было...
8 авг 07, 11:01    [4494719]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
dmidek
Member

Откуда: Киев - Дортмунд
Сообщений: 116299
tru55
не обязательно, только в 8 join-а не было...


... и особенно в девятке синтаксис join содержит много багов. Использовать надо
очень аккуратно.
8 авг 07, 11:03    [4494739]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Jannny
Member

Откуда: Спб
Сообщений: 6424
26IVC
говорят что он из MSSQL
Он не из MSSQL-я, а из ANSI-SQL-я :)
8 авг 07, 11:03    [4494742]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
trak
Member

Откуда: spb.ru
Сообщений: 802
dmidek
tru55
не обязательно, только в 8 join-а не было...


... и особенно в девятке синтаксис join содержит много багов. Использовать надо
очень аккуратно.

При том, особенно "приятно", что в доке черным по белому рекомендуется использовать ansi join.
8 авг 07, 11:14    [4494839]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
GKS_Samara
Member

Откуда: Самара
Сообщений: 2790

26IVC wrote:

> Использую join, говорят что он из MSSQL, что мне обязательно переходить
> на синтаксис (+)?

Как привычно- я вот с firebird пришёл- плохеет от вида (+), кто работал
с 8кой- шизеет от left outer join.

Реально- один раз план хреновый был с inner join и нормальный с
неявным. 9.2.0.8

Ну и от смеси явных и неявных сносит крышу точно.

--
Алексей

Posted via ActualForum NNTP Server 1.4

8 авг 07, 11:21    [4494894]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Stax..
Guest
26IVC
Использую join, говорят что он из MSSQL, что мне обязательно переходить на синтаксис (+)?

врут

1)главна проблема глюки в оракле с full join
2)(+) более сильные ограничения (напр in/or)
3)оракле рекомендует забить на (+)

Oracle recommends that you use the FROM clause OUTER JOIN syntax rather than the Oracle join operator. Outer join queries that use the Oracle join operator (+) are subject to the following rules and restrictions, which do not apply to the FROM clause OUTER JOIN syntax:


.....
stax
8 авг 07, 12:46    [4495635]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Вадиман
Member

Откуда: Владивосток
Сообщений: 1072
Еще какой-то баг был, связанный с ansi-шным синтаксисом внешнего соединения нескольких таблиц. Запрос мог вернуть ВООБЩЕ БРЕД. На Oracle 10.1.

Использовать-то все равно хочется, ansi-шный синтаксис более... гм... функционален. Как, например, реализовать такое вот при помощи (+) для внешнего соединения?

SELECT a.*
FROM   table1 a LEFT OUTER JOIN table2 b ON a.id = b.table1_id AND b.class = 1;

Придется юзать NVL с допущением, что колонка b.class не может содержать NULLs. А если может? Как отличить?
9 авг 07, 11:44    [4501027]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Jannny
Member

Откуда: Спб
Сообщений: 6424
Вадиман
Как, например, реализовать такое вот при помощи (+) для внешнего соединения?

SELECT a.*
FROM   table1 a LEFT OUTER JOIN table2 b ON a.id = b.table1_id AND b.class = 1;

Придется юзать NVL с допущением, что колонка b.class не может содержать NULLs. А если может? Как отличить?
И в чем в данном пример трабл??? Причем тут NVL - не догоняю
b.class(+) = 1
9 авг 07, 11:52    [4501103]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Вадиман
Member

Откуда: Владивосток
Сообщений: 1072
Jannny
Вадиман
Как, например, реализовать такое вот при помощи (+) для внешнего соединения?

SELECT a.*
FROM   table1 a LEFT OUTER JOIN table2 b ON a.id = b.table1_id AND b.class = 1;

Придется юзать NVL с допущением, что колонка b.class не может содержать NULLs. А если может? Как отличить?
И в чем в данном пример трабл??? Причем тут NVL - не догоняю
b.class(+) = 1


Упс...
виноват, сорри

Я как-то пробовал так сделать, видимо, в чем-то другом напорол, но в голове отложился факт, что так сделать нельзя (с константами).
9 авг 07, 12:11    [4501282]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
andy_versal
Member

Откуда: оттуда...
Сообщений: 113
Stax..
1)главна проблема глюки в оракле с full join

кстати, а 10.2.0.3 это ещё не пофиксили? кто знает?
9 авг 07, 12:22    [4501379]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Салага
Member

Откуда:
Сообщений: 134
Если кто то сдавал экзамен по 01z-007, то наверно помнят что там есть вопрос на JOINы, так вот там правильным является ответ с JOINнами, хотя присутствует такой де запрос с (+). т.е. сам оракел так считает и к тому же это как уже написали MSSQL здесь нипричем это определение ANSI. Какие тут еще вопросы могут быть?
9 авг 07, 12:24    [4501395]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
kennethr
Member

Откуда:
Сообщений: 175
Вадиман
что так сделать нельзя (с константами).

Наверное пробовали заменить
select * from my_table t where nvl(t.my_field,0) = 0
на
select * from my_table t where t.my_field(+) = 0
9 авг 07, 12:29    [4501436]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 64002
Блог
Вадиман
Я как-то пробовал так сделать, видимо, в чем-то другом напорол, но в голове отложился факт, что так сделать нельзя (с константами).

Между left outer join и (+) нет функциональной разницы; в свое время в "Сравнении СУБД" ее долго искали и не нашли. Просто - некоторые вещи формулируются иначе, в частности иногда надо выделять подзапрос.
9 авг 07, 12:33    [4501467]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Sk(A)
Member

Откуда:
Сообщений: 593
Stax..
1)главна проблема глюки в оракле с full join

В 10-ке вроде починили...Или я не прав ?
9 авг 07, 12:37    [4501512]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Elic
Member

Откуда:
Сообщений: 29990
Вадиман
в голове отложился факт, что так сделать нельзя (с константами).
Можно и более сложные условия: STFF Что делает конструкция (+) ???
9 авг 07, 12:38    [4501521]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Stax..
Guest
Вадиман
Еще какой-то баг был, связанный с ansi-шным синтаксисом внешнего соединения нескольких таблиц. Запрос мог вернуть ВООБЩЕ БРЕД. На Oracle 10.1.

Использовать-то все равно хочется, ansi-шный синтаксис более... гм... функционален. Как, например, реализовать такое вот при помощи (+) для внешнего соединения?

SELECT a.*
FROM   table1 a LEFT OUTER JOIN table2 b ON a.id = b.table1_id AND b.class = 1;

Придется юзать NVL с допущением, что колонка b.class не может содержать NULLs. А если может? Как отличить?

согласен что JOIN шире

но с примером что-то туплю,
какая проблема с b.class(+)=1
мона на нескольких строках, для общего развития
......
stax
9 авг 07, 12:40    [4501541]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
Вадиман
Member

Откуда: Владивосток
Сообщений: 1072
Да этой мой глюк :) Выше уже ответил
Но честно говоря, пребывал в такой уверенности целый год :D
10 авг 07, 05:13    [4505759]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
andy_versal
Member

Откуда: оттуда...
Сообщений: 113
Sk(A)
Stax..
1)главна проблема глюки в оракле с full join

В 10-ке вроде починили...Или я не прав ?


неа, не починили... по крайней мере, на 10.2.0.3 ora-600 регулярно посещает... так что низзя фулл пока ещё пользовать.
10 авг 07, 09:36    [4506087]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
шубин_ду
Member

Откуда: Питер->Кобург
Сообщений: 200
У меня тут текст по теме завалялся. Когда-то писал брошюру для практикантов. Может пригодится кому.

ANSI может пригодиться в таком случае:

Внутреннее соединение после внешнего


Имеем таблицу A, слабо связанную с B. Это означает, что не для всех записей A существуют записи в B. Но таблица B сильно связана с C. Это значит, что при отборе записи из B надо проверять, что для нее есть запись в C. Если нет, то такие строки из B отбирать не надо.

В обычном синтаксисе можно задать слабую связь A и B через (+), но одновременно задать сильную связь между B и C не получится. Результат будет неверный.

Пример

create table test_a ( internalid number(10) );
create table test_b ( internalid number(10), a_internalid number(10) );
create table test_c ( internalid number(10), b_internalid number(10) );

insert into test_a values( 1 );
insert into test_a values( 2 );
insert into test_b values( 1, 1 );
insert into test_b values( 2, 1 );
insert into test_c values( 1, 1 );
commit;
Нам нужно построить select, который бы отбирал записи из таблицы a. При этом запись а должна быть отобрана независимо от того есть у нее запись в b или нет. Но если запись в b существует, то она должна иметь запись (или записи) в c.

Как видно запись a.2 не имеет записи в b, но она должна быть отобрана.
Запись b.2 не имеет записи в c поэтому она не должна быть отобрана.

Мы ожидаем получить такой результат:

A_INTERNALID B_INTERNALID C_INTERNALID
------------ ------------ ------------
           1            1            1
           2


Сначала построим селект для отбора записей только из a и b.

select
   test_a.internalid as a_internalid,
   test_b.internalid as b_internalid
from
   test_a,
   test_b
where
   test_a.internalid = test_b.a_internalid (+)
;

17:20:13 my@db SID:38> select
17:20:14   2     test_a.internalid as a_internalid,
17:20:14   3     test_b.internalid as b_internalid
17:20:14   4  from
17:20:14   5     test_a,
17:20:14   6     test_b
17:20:14   7  where
17:20:14   8     test_a.internalid = test_b.a_internalid (+)
17:20:14   9  ;

A_INTERNALID B_INTERNALID
------------ ------------
           1            1
           1            2
           2

17:20:15 my@db SID:38>

Пока все работает верно. Запись a.2 отобрана, хотя у нее и нет записей в b.

Добавим таблицу c.

select
   test_a.internalid as a_internalid,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid
from
   test_a,
   test_b,
   test_c
where
       test_a.internalid = test_b.a_internalid (+)
   and test_b.internalid = test_c.b_internalid (+)
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;

17:20:15 my@db SID:38> select
17:23:49   2     test_a.internalid as a_internalid,
17:23:49   3     test_b.internalid as b_internalid,
17:23:49   4     test_c.internalid as c_internalid
17:23:49   5  from
17:23:49   6     test_a,
17:23:49   7     test_b,
17:23:49   8     test_c
17:23:49   9  where
17:23:49  10         test_a.internalid = test_b.a_internalid (+)
17:23:49  11     and test_b.internalid = test_c.b_internalid (+)
17:23:49  12  order by
17:23:49  13     test_a.internalid,
17:23:49  14     test_b.internalid,
17:23:49  15     test_c.internalid
17:23:49  16  ;

A_INTERNALID B_INTERNALID С_INTERNALID
------------ ------------ ------------
           1            1            1
           1            2
           2

17:23:50 my@db SID:38>
Результат неверный!

Таблицы b и с по условию жестко связаны. Так как b.2 не имеет связи с таблицей c, то она не должна попасть в результат. Поэтому результат для a.1 выдан неверно. Только сочетание a1-b.1 должно попасть в ответ.
Попробуем установить жесткую связь исправив внешнее соединение на внутреннее.

select
   test_a.internalid as a_internalid,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid
from
   test_a,
   test_b,
   test_c
where
       test_a.internalid = test_b.a_internalid (+)
   and test_b.internalid = test_c.b_internalid
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;
Мы убрали (+) во второй строке.

17:23:50 my@db SID:38> select
17:27:07   2     test_a.internalid as a_internalid,
17:27:07   3     test_b.internalid as b_internalid,
17:27:07   4     test_c.internalid as c_internalid
17:27:07   5  from
17:27:07   6     test_a,
17:27:07   7     test_b,
17:27:07   8     test_c
17:27:07   9  where
17:27:07  10         test_a.internalid = test_b.a_internalid (+)
17:27:07  11     and test_b.internalid = test_c.b_internalid
17:27:07  12  order by
17:27:07  13     test_a.internalid,
17:27:07  14     test_b.internalid,
17:27:07  15     test_c.internalid
17:27:07  16  ;

A_INTERNALID B_INTERNALID C_INTERNALID
------------ ------------ ------------
           1            1            1

17:27:08 my@db SID:38>
Для a.1 мы получили верный результат. Но теперь пропал a.2. Дело в том, что теперь задана жесткая связь для b и c. Но a.2 не имеет связи с b, поэтому второе условие для него не выполняется.

Используем ANSI синтаксис для решения этой задачи.

select
   test_a.internalid as a_internalid,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid
from
   test_a left outer join (
      test_b inner join test_c
         on test_b.internalid = test_c.b_internalid
   ) on test_a.internalid = test_b.a_internalid
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;

17:38:38 my@db SID:38> select
17:39:03   2     test_a.internalid as a_internalid,
17:39:03   3     test_b.internalid as b_internalid,
17:39:03   4     test_c.internalid as c_internalid
17:39:03   5  from
17:39:03   6     test_a left outer join (
17:39:03   7        test_b inner join test_c
17:39:03   8           on test_b.internalid = test_c.b_internalid
17:39:03   9     ) on test_a.internalid = test_b.a_internalid
17:39:03  10  order by
17:39:03  11     test_a.internalid,
17:39:03  12     test_b.internalid,
17:39:03  13     test_c.internalid
17:39:03  14  ;

A_INTERNALID B_INTERNALID C_INTERNALID
------------ ------------ ------------
           1            1            1
           2

17:39:03 my@db SID:38>

Результат верный.

Тот же результат можно было бы получить через правое объединение

select
   test_a.internalid as a_internalid,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid
from
   ( test_b inner join test_c
         on test_b.internalid = test_c.b_internalid )
    right outer join test_a on test_a.internalid = test_b.a_internalid
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;

17:39:03 my@db SID:38> select
17:41:09   2     test_a.internalid as a_internalid,
17:41:09   3     test_b.internalid as b_internalid,
17:41:09   4     test_c.internalid as c_internalid
17:41:09   5  from
17:41:09   6     ( test_b inner join test_c
17:41:09   7           on test_b.internalid = test_c.b_internalid )
17:41:09   8      right outer join test_a on test_a.internalid = test_b.a_internalid
17:41:09   9  order by
17:41:09  10     test_a.internalid,
17:41:09  11     test_b.internalid,
17:41:09  12     test_c.internalid
17:41:09  13  ;

A_INTERNALID B_INTERNALID C_INTERNALID
------------ ------------ ------------
           1            1            1
           2

17:41:10 my@db SID:38>
Скобки в предложении FROM даны для наглядности. Можно и без них:

select
   test_a.internalid as a_internalid,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid
from
   test_a left outer join test_b inner join test_c
   on test_b.internalid = test_c.b_internalid
   on test_a.internalid = test_b.a_internalid
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;

17:43:05 my@db SID:38> select
17:43:11   2     test_a.internalid as a_internalid,
17:43:11   3     test_b.internalid as b_internalid,
17:43:11   4     test_c.internalid as c_internalid
17:43:11   5  from
17:43:11   6     test_a left outer join test_b inner join test_c
17:43:11   7     on test_b.internalid = test_c.b_internalid
17:43:11   8     on test_a.internalid = test_b.a_internalid
17:43:11   9  order by
17:43:11  10     test_a.internalid,
17:43:11  11     test_b.internalid,
17:43:11  12     test_c.internalid
17:43:11  13  ;

A_INTERNALID B_INTERNALID C_INTERNALID
------------ ------------ ------------
           1            1            1
           2

17:43:12 my@db SID:38>

select
   test_a.internalid as a_internalid,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid
from
   test_b inner join test_c on test_b.internalid = test_c.b_internalid 
   right outer join test_a on test_a.internalid = test_b.a_internalid
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;
17:41:10 my@db SID:38> select
17:42:29   2     test_a.internalid as a_internalid,
17:42:29   3     test_b.internalid as b_internalid,
17:42:29   4     test_c.internalid as c_internalid
17:42:29   5  from
17:42:29   6     test_b inner join test_c on test_b.internalid = test_c.b_internalid
17:42:29   7     right outer join test_a on test_a.internalid = test_b.a_internalid
17:42:29   8  order by
17:42:29   9     test_a.internalid,
17:42:29  10     test_b.internalid,
17:42:29  11     test_c.internalid
17:42:29  12  ;

A_INTERNALID B_INTERNALID C_INTERNALID
------------ ------------ ------------
           1            1            1
           2

17:42:30 my@db SID:38>
Таким образом в ANSI синтаксисе можно сочетать сильную связь со слабой для случая: A -> слабая связь с B -> сильная связь с C.

Транзитивное внешнее соединение

Изменим задание. Пусть теперь между таблицей b и c существует слабая связь (в первом примере связь была сильной). Это означает, что записи из b нужно показывать даже если нет соответствующей записи в c.

Однако введем зависимость между c и a.

Расширим таблицы a и c колонкой code. И наложим жесткое условие:

a.code = c.code

create table test_a ( internalid number(10), code varchar2(5) );
create table test_b ( internalid number(10), a_internalid number(10) );
create table test_c ( internalid number(10), b_internalid number(10), code varchar2(5) );
Т.е. если для b нет записи в c, то надо отбирать b. Но если запись в с есть, то отбирать надо только те записи из c, у которых код равен коду в a.

delete test_a;
delete test_b;
delete test_c;
insert into test_a values( 1, 'abc' );
insert into test_a values( 2, 'def' );
insert into test_b values( 1, 1 );
insert into test_b values( 2, 1 );
insert into test_c values( 1, 1, 'abc' );
insert into test_c values( 2, 1, 'klm' );
commit;

Ожидаемый результат:

A_INTERNALID A_COD B_INTERNALID C_INTERNALID C_COD
------------ ----- ------------ ------------ -----
           1 abc              1            1 abc
           1 abc              2
           2 def

Сначала сделаем запрос без ограничения на код.

select
   test_a.internalid as a_internalid,
   test_a.code as a_code,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid,
   test_c.code as c_code
from
   test_a,
   test_b,
   test_c
where
       test_a.internalid = test_b.a_internalid (+)
   and test_b.internalid = test_c.b_internalid (+)
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;

17:43:12 my@db SID:38> select
17:59:25   2     test_a.internalid as a_internalid,
17:59:25   3     test_a.code as a_code,
17:59:25   4     test_b.internalid as b_internalid,
17:59:25   5     test_c.internalid as c_internalid,
17:59:25   6     test_c.code as c_code
17:59:25   7  from
17:59:25   8     test_a,
17:59:25   9     test_b,
17:59:25  10     test_c
17:59:25  11  where
17:59:25  12         test_a.internalid = test_b.a_internalid (+)
17:59:25  13     and test_b.internalid = test_c.b_internalid (+)
17:59:25  14  order by
17:59:25  15     test_a.internalid,
17:59:25  16     test_b.internalid,
17:59:25  17     test_c.internalid
17:59:25  18  ;

A_INTERNALID A_COD B_INTERNALID C_INTERNALID C_COD
------------ ----- ------------ ------------ -----
           1 abc              1            1 abc
           1 abc              1            2 klm
           1 abc              2
           2 def

17:59:26 my@db SID:38>
Как видно в ответ попала одна лишняя запись. Ее нужно откинуть, так как ее код не совпадает с кодом a.

Попробуем сделать это так:

select
   test_a.internalid as a_internalid,
   test_a.code as a_code,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid,
   test_c.code as c_code
from
   test_a,
   test_b,
   test_c
where
       test_a.internalid = test_b.a_internalid (+)
   and test_b.internalid = test_c.b_internalid (+)
   and test_a.code       = test_c.code (+)
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;
Получим ошибку.

17:59:26 my@db SID:38> select
18:05:29   2     test_a.internalid as a_internalid,
18:05:29   3     test_a.code as a_code,
18:05:29   4     test_b.internalid as b_internalid,
18:05:29   5     test_c.internalid as c_internalid,
18:05:29   6     test_c.code as c_code
18:05:29   7  from
18:05:29   8     test_a,
18:05:29   9     test_b,
18:05:29  10     test_c
18:05:29  11  where
18:05:29  12         test_a.internalid = test_b.a_internalid (+)
18:05:29  13     and test_b.internalid = test_c.b_internalid (+)
18:05:29  14     and test_a.code       = test_c.code (+)
18:05:29  15  order by
18:05:29  16     test_a.internalid,
18:05:29  17     test_b.internalid,
18:05:29  18     test_c.internalid
18:05:29  19  ;
   and test_b.internalid = test_c.b_internalid (+)
                         *
FEHLER in Zeile 13:
ORA-01417: a table may be outer joined to at most one other table
Мы пытаемся сделать внешнее соединение между a и с в то время когда уже существует внешнее соединение между а и b и между b и c. Транзитивное внешнее соединение в обычном синтаксисе невозможно.

Попробуем без внешнего соединения по условию между a и c.

select
   test_a.internalid as a_internalid,
   test_a.code as a_code,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid,
   test_c.code as c_code
from
   test_a,
   test_b,
   test_c
where
       test_a.internalid = test_b.a_internalid (+)
   and test_b.internalid = test_c.b_internalid (+)
   and test_a.code       = test_c.code
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;
Мы убрали (+) в третьей строке.

18:05:30 my@db SID:38> select
18:07:24   2     test_a.internalid as a_internalid,
18:07:24   3     test_a.code as a_code,
18:07:24   4     test_b.internalid as b_internalid,
18:07:24   5     test_c.internalid as c_internalid,
18:07:24   6     test_c.code as c_code
18:07:24   7  from
18:07:24   8     test_a,
18:07:24   9     test_b,
18:07:24  10     test_c
18:07:24  11  where
18:07:24  12         test_a.internalid = test_b.a_internalid (+)
18:07:24  13     and test_b.internalid = test_c.b_internalid (+)
18:07:24  14     and test_a.code       = test_c.code
18:07:24  15  order by
18:07:24  16     test_a.internalid,
18:07:24  17     test_b.internalid,
18:07:24  18     test_c.internalid
18:07:24  19  ;

A_INTERNALID A_COD B_INTERNALID C_INTERNALID C_COD
------------ ----- ------------ ------------ -----
           1 abc              1            1 abc

18:07:24 my@db SID:38>
Результат неверный. Пропали записи a1-b2 и a2.

Используем ANSI синтаксис.

select
   test_a.internalid as a_internalid,
   test_a.code as a_code,
   test_b.internalid as b_internalid,
   test_c.internalid as c_internalid,
   test_c.code as c_code
from
   test_a
   left outer join test_b on
      test_a.internalid = test_b.a_internalid
   left outer join test_c on
      test_b.internalid = test_c.b_internalid and
      test_a.code = test_c.code
order by 
   test_a.internalid,
   test_b.internalid,
   test_c.internalid
;

18:07:24 my@db SID:38> select
18:16:03   2     test_a.internalid as a_internalid,
18:16:03   3     test_a.code as a_code,
18:16:03   4     test_b.internalid as b_internalid,
18:16:03   5     test_c.internalid as c_internalid,
18:16:03   6     test_c.code as c_code
18:16:03   7  from
18:16:03   8     test_a
18:16:03   9     left outer join test_b on
18:16:03  10        test_a.internalid = test_b.a_internalid
18:16:03  11     left outer join test_c on
18:16:03  12        test_b.internalid = test_c.b_internalid and
18:16:03  13        test_a.code = test_c.code
18:16:03  14  order by
18:16:03  15     test_a.internalid,
18:16:03  16     test_b.internalid,
18:16:03  17     test_c.internalid
18:16:03  18  ;

A_INTERNALID A_COD B_INTERNALID C_INTERNALID C_COD
------------ ----- ------------ ------------ -----
           1 abc              1            1 abc
           1 abc              2
           2 def

18:16:03 my@db SID:38>
Ответ правильный.
10 авг 07, 20:47    [4511080]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 64002
Блог
шубин_ду
У меня тут текст по теме завалялся. Когда-то писал брошюру для практикантов.

Бедные практиканты. Вот так и рождаются легенды про "не может", "не умеет"...

шубин_ду
В обычном синтаксисе можно задать слабую связь A и B через (+), но одновременно задать сильную связь между B и C не получится. Результат будет неверный. Пример

SQL> select a.internalid, bc.b_internalid, bc.c_internalid
  2  from test_a a,
  3       (select a_internalid,
  4               test_b.internalid b_internalid,
  5               test_c.internalid c_internalid
  6        from test_b, test_c
  7        where test_b.internalid = test_c.b_internalid) bc
  8  where a.internalid = bc.a_internalid(+)
  9  ;

 INTERNALID B_INTERNALID C_INTERNALID
----------- ------------ ------------
          1            1            1
          2              

Пример: ищем десять отличий приведенного результата от объявленного верным.

шубин_ду
Транзитивное внешнее соединение

Изменим задание. .....

SQL> select ab.a_internalid, ab.a_code, ab.b_internalid, c.internalid, c.code
  2  from (select a.internalid a_internalid,
  3               a.code a_code,
  4               b.internalid b_internalid
  5        from test_a a, test_b b
  6        where a.internalid = b.a_internalid(+)) ab,
  7       test_c c
  8  where ab.b_internalid = c.b_internalid(+) and ab.a_code = c.code(+)
  9  ;

A_INTERNALID A_CODE B_INTERNALID  INTERNALID CODE
------------ ------ ------------ ----------- -----
           1 abc               1           1 abc
           2 def                             
           1 abc               2             
Пример: ищем десять отличий приведенного результата от объявленного верным.
10 авг 07, 21:24    [4511155]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
шубин_ду
Member

Откуда: Питер->Кобург
Сообщений: 200
softwarer
[quot шубин_ду]У меня тут текст по теме завалялся. Когда-то писал брошюру для практикантов.

Бедные практиканты. Вот так и рождаются легенды про "не может", "не умеет"...

[quot шубин_ду]

Не надо передергивать. Речь шла не о "может", "не может", а о соединениях. Сделайте эти два примера без внутренних селектов, только на оракловских соединениях. Вот тогда и пишите про бедных практикантов.
10 авг 07, 22:13    [4511308]     Ответить | Цитировать Сообщить модератору
 Re: что лучше использовать join или (+)  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 64002
Блог
шубин_ду
Не надо передергивать. Речь шла не о "может", "не может", а о соединениях.

Cтало быть, Вы выдумываете противоестественные дополнительные условия, но при этом я передергиваю. Забавно.

Довольно точным аналогом ситуации является сравнение обычного арифметического синтаксиса с польской записью. Как известно, она позволяет обойтись без скобок (равно как и ansi-синтаксис), и это утверждение никаких вопросов бы не вызвало.

Вы вместо этого говорите примерно следующее: "обычный арифметический синтаксис не позволит выполнить умножение после сложения", а когда напарываетесь на пример обратного - добавляете про "скобки не использовать".
10 авг 07, 22:24    [4511353]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить