Oracle Поиск совпадения строк из нескольких таблиц базы данных - PullRequest
1 голос
/ 08 ноября 2019

Это довольно сложная проблема для описания, но я попытаюсь объяснить это на примере. Я думал, что смог бы использовать функцию Oracle Instr для этого, но он не принимает запросы в качестве параметров.

Вот упрощение моих данных:

  Table1
   Person         Qualities
   Joe            5,6,7,8,9
   Mary           7,8,10,15,20
   Bob            7,8,9,10,11,12

   Table2
   Id             Desc
   5              Nice
   6              Tall
   7              Short

   Table3
   Id             Desc
   8              Angry
   9              Sad
   10             Fun

   Table4
   Id             Desc
   11             Boring    
   12             Happy
   15             Cool
   20             Mad

ЗдесьЭто своего рода запрос, чтобы дать представление о том, чего я пытаюсь достичь:

   select * from table1 
   where instr (Qualities, select Id from table2, 1,1) <> 0
   and instr (Qualities, select Id from table3, 1,1) <> 0 
   and instr (Qualities, select Id from table3, 1,1) <> 0

Я пытаюсь выяснить, у каких людей есть хотя бы 1 качество из каждой из 3 групп качеств (таблицы 2,3 и 4)

Таким образом, Джо не будет возвращен в результатах, потому что у него нет качества от каждой из 3 групп, но у Мэри и Джо будет, поскольку у них есть по крайней мере 1 качество откаждая группа.

Мы используем Oracle 12, спасибо!

Ответы [ 2 ]

1 голос
/ 08 ноября 2019

Вот один из вариантов:

SQL> with
  2  table1 (person, qualities) as
  3    (select 'Joe', '5,6,7,8,9' from dual union all
  4     select 'Mary', '7,8,10,15,20' from dual union all
  5     select 'Bob', '7,8,9,10,11,12' from dual
  6    ),
  7  table2 (id, descr) as
  8    (select 5, 'Nice' from dual union all
  9     select 6, 'Tall' from dual union all
 10     select 7, 'Short' from dual
 11    ),
 12  table3 (id, descr) as
 13    (select 8, 'Angry' from dual union all
 14     select 9, 'Sad' from dual union all
 15     select 10, 'Fun' from dual
 16    ),
 17  table4 (id, descr) as
 18    (select 11, 'Boring' from dual union all
 19     select 12, 'Happy' from dual union all
 20     select 15, 'Cool' from dual union all
 21     select 20, 'Mad' from dual
 22    ),
 23  t1new (person, id) as
 24    (select person, regexp_substr(qualities, '[^,]+', 1, column_value) id
 25     from table1 cross join table(cast(multiset(select level from dual
 26                                                connect by level <= regexp_count(qualities, ',') + 1
 27                                               ) as sys.odcinumberlist))
 28    )
 29  select a.person,
 30        count(b.id) bid,
 31        count(c.id) cid,
 32        count(d.id) did
 33  from t1new a left join table2 b on a.id = b.id
 34               left join table3 c on a.id = c.id
 35               left join table4 d on a.id = d.id
 36  group by a.person
 37  having (    count(b.id) > 0
 38          and count(c.id) > 0
 39          and count(d.id) > 0
 40         );

PERS        BID        CID        DID
---- ---------- ---------- ----------
Bob           1          3          2
Mary          1          2          2

SQL>

Что это делает?

  • строки # 1 - 22 представляют ваши данные выборки
  • T1NEW CTE (строки # 23 - 28) разбивают разделенные запятыми качества на строки, для каждого человека
  • final select (строки # 29 - 40) являются внешними соединениями t1new с каждой из таблиц "описания" (table2/3/4) и подсчитывает, сколько качеств содержится в нем для каждого из качеств человека (представлено строками из t1new)
  • having здесь для возврата только желаемых лиц;каждый из этих показателей должен быть положительным числом
0 голосов
/ 09 ноября 2019

Может быть, это поможет: {1} Создать представление, которое классифицирует все качества и позволяет ВЫБРАТЬ идентификаторы качества и категории. {2} Присоедините представление к TABLE1 и используйте условие соединения, которое «разбивает» значение CSV, хранящееся в TABLE1.

{1} Просмотр

create or replace view allqualities
as
select 1 as category, id as qid, descr from table2
union
select 2, id, descr from table3
union
select 3, id, descr from table4
;

select * from allqualities order by category, qid ;

  CATEGORY        QID DESCR 
---------- ---------- ------
         1          5 Nice  
         1          6 Tall  
         1          7 Short 
         2          8 Angry 
         2          9 Sad   
         2         10 Fun   
         3         11 Boring
         3         12 Happy 
         3         15 Cool  
         3         20 Mad 

{2} Запрос

--  JOIN CONDITION:
--  {1} add a comma at the start and at the end of T1.qualities
--  {2} remove all blanks (spaces) from T1.qualities
--  {3} use LIKE and the qid (of allqualities), wrapped in commas
--
--  inline view: use UNIQUE, otherwise we may get counts > 3
--

select person
from (
  select unique person, category
  from table1 T1 
    join allqualities A 
      on ',' || replace( T1.qualities, ' ', '' ) || ',' like '%,' || A.qid || ',%'
)
group by person
having count(*) = ( select count( distinct category ) from allqualities )
;

-- result
PERSON   
Bob      
Mary 

Проверено с Oracle 18c и 11g. DBfiddle здесь .

...