SQL Левое внешнее соединение не возвращает все строки из левой таблицы (без фильтра предложения where)

#sql #oracle #left-join

Вопрос:

У меня есть левое внешнее соединение, которое возвращает не все строки из «левой» таблицы. У меня нет предложения where, поэтому после соединения не следует применять фильтрацию.

Я ожидаю:

Продукт 1 около 100
Продукт 2 около 25
Продукт 4 около 57
Продукт 1 gr 45
Продукт 2 gr 22
Продукт 3 gr 5
Продукт 4 gr 4
Продукт 3 нулевой нулевой

Но я пропускаю последний ряд. Любой свет, который вы могли бы пролить на это, очень ценится.

Чтобы воспроизвести его:

 -- Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

drop table t1;
drop table t2;


create table t1 
(ov_product          varchar2(18 byte)
,product             varchar2(18 byte)
)
/

create table t2 
(reporting_month     number
,product             varchar2(18 byte) 
,sender              varchar2(2 byte) 
,items               number 
)
/

insert into t1
(
select 'Product 1' ov_product, 'P1' product from dual
union
select 'Product 2' ov_product, 'P2' product from dual
union
select 'Product 3' ov_product, 'P3' product from dual
union
select 'Product 4' ov_product, 'P4' product from dual
);

insert into t2
(
select 202108, 'P1', 'AT', 100 from dual
union
select 202108, 'P2', 'AT', 25 from dual
union
-- no P3 for AT
select 202108, 'P4', 'AT', 57 from dual
union
select 202108, 'P1', 'GR', 45 from dual
union
select 202108, 'P2', 'GR', 22 from dual
union
select 202108, 'P3', 'GR', 5 from dual
union
select 202108, 'P4', 'GR', 4 from dual
)
;
commit;
 
 select t1.ov_product
      ,t2.sender
      ,t2.items
  from t1
  left outer join t2
    on t1.product = t2.product
 order by 2, 1   
;
 

Ответ №1:

Ваше внешнее соединение работает нормально.

Вы, вероятно, имеете в виду секционированное внешнее соединение.

Смотрите дополнительные query_partition_clause в соединении

PARTITION BY (sender) только это соединение заполнит пробелы, sender как вы и ожидали.

 select t1.ov_product
      ,t2.sender
      ,t2.items
  from t1
  left outer join t2
  PARTITION BY  (sender)
    on t1.product = t2.product   
 order by 2, 1


OV_PRODUCT         SE      ITEMS
------------------ -- ----------
Product 1          AT        100
Product 2          AT         25
Product 3          AT           
Product 4          AT         57
Product 1          GR         45
Product 2          GR         22
Product 3          GR          5
Product 4          GR          4
 

Ответ №2:

Так как в t2 есть строка с продуктом 3, нет записи с нулевым значением, которую нужно создать с помощью соединения слева.

Чтобы получить такую строку, вам нужно либо присоединиться к таблице отправителей, если она у вас есть. Или, если таблица не существует, вы можете использовать CTE, как это

с отправителями(отправителем) как (выберите отдельный отправитель из t2)

 with senders(sender) as (select distinct sender from t2)

select t1.ov_product
      ,t2.sender
      ,t2.items
  from t1
  cross join senders
  left outer join t2
    on t1.product = t2.product
   and t2.sender = senders.sender
 order by 2, 1;