Oracle join возвращает слишком много строк

#oracle #inner-join

#Oracle #inner-join

Вопрос:

У меня есть следующие параметры выбора в Oracle 19:

 select count(*) as facility_load_stg_cnt from facility_load_stg;

select count(*) as facility_cnt from facility;

select count(*) as loctn_typ_cnt from loctn_typ;

select count(*) as join_cnt from (
select f.facility_id, lt.loctn_typ_id
from facility_load_stg stg
inner join facility f on stg.facility_cd = f.facility_cd
inner join loctn_typ lt on stg.bldg = lt.loctn_typ_nm);
 

задача проста, получите PK для facility и loctn_typ (facility_id, loctn_typ_id) для вставки в таблицу, которая будет строить отношения.

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

 
FACILITY_LOAD_STG_CNT
---------------------
                  987


FACILITY_CNT
------------
         645


LOCTN_TYP_CNT
-------------
          188


  JOIN_CNT
----------
      2905
 

почему выбор с соединением в 3 раза превышает строки таблицы facility_load_stg? Я уверен, что делаю что-то глупое, я просто не вижу этого.

Люди попросили посмотреть определения таблиц, вот соответствующие части:

 create table FACILITY_MAINT_DATA.FACILITY_LOAD_STG
(
    FACILITY_CD VARCHAR2(100) not null,
    BLDG VARCHAR2(100)
)

create table FACILITY_MAINT_DATA.FACILITY
(
    FACILITY_CD VARCHAR2(100),
    FACILITY_ID NUMBER(14) not null
        constraint PK_FACILITY
            primary key
)

create table FACILITY_MAINT_DATA.LOCTN_TYP
(
    LOCTN_TYP_ID NUMBER(14) default "FACILITY_MAINT_DATA"."LOCTN_TYP_ID_SEQ"."NEXTVAL" not null
        constraint PK_LOCTN_TYP
            primary key,
    LOCTN_TYP_NM VARCHAR2(100),
)
 

Комментарии:

1. Каковы ваши определения таблиц и как выглядят ваши данные? Предположительно, вы присоединяетесь к чему-то, кроме первичного ключа. Если несколько строк в f или в lt соответствуют критериям объединения для одной строки в stg , ваше объединение будет генерировать больше строк, чем в stg .

2. Мы не можем ответить, но мы можем строить предположения. Вы не объяснили, что это за *_cd вещи и почему вы объединяетесь с ними вместо *_id столбцов, если это первичные ключи. Например, несколько объектов могут иметь один и тот же «код» (догадываясь, что может означать «cd»), даже если они являются разными объектами. В этом случае соединение, вероятно, неправильное / неправильное / не делает то, что вы думаете.

3. Попробуйте что-то вроде select facility_cd,count( ) из facility_cnt group с помощью facility_cd; и выберите loctn_typ_nm,count( ) из loctn_typ_cnt group с помощью loctn_typ_nm; — если вы видите значение facility_cd или loctn_typ_nm со значением count> 1, то вы знаете, что соединение из facility_load_stg_cnt в этих столбцах может присоединяться к нескольким строкам вэти таблицы.

Ответ №1:

Общее правило, если вы присоединяетесь и сталкиваетесь с более высоким числом, чем ожидаете, заключается в том, что ключи объединения не являются уникальными*

Вот простой пример, воспроизводящий тот же результат, что и у вас (ограничение только двумя таблицами).

 create table tab1 as
select rownum id, 
case when rownum <= 80 then 'CD_'||rownum else 'CD_X' end cd from dual connect by level <= 645;

create table tab2 as
select rownum id, 
case when rownum <= 80 then 'CD_'||rownum 
when rownum <= 85 then 'CD_X'
else 'CD_Y' end cd from dual connect by level <= 987;

select count(*) from tab1;

  COUNT(*)
----------
       645

select count(*) from tab2;

  COUNT(*)
----------
       987

select count(*) 
from tab1
join tab2
on tab1.cd = tab2.cd;

  COUNT(*)
----------
      2905
 

Сводка измените объединение, чтобы использовать уникальные ключи, или ограничьте объединение только такими CD уникальными столбцами.

Ответ №2:

Спасибо всем за комментарии, которые заставили меня детально рассмотреть фактические данные и выявить дублирование. Теперь мне просто нужно выяснить, почему, просто нужно провести небольшое расследование 🙂