Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Jak powiązać poziome wartości tabeli z pionowymi wartościami innej tabeli w bazie danych Oracle?

with a as (
    select a.*, row_number() over (partition by department order by attributeID) rn
      from attributes a),
  e as (
    select employeeId, department, attribute1, 1 rn from employees union all
    select employeeId, department, attribute2, 2 rn from employees union all
    select employeeId, department, attribute3, 3 rn from employees
  )
select e.employeeId, a.attributeid, e.department, a.attribute, a.meaning, 
       e.attribute1 as value 
  from e join a on a.department=e.department and a.rn=e.rn 
  order by e.employeeId, a.attributeid

Dane testowe i dane wyjściowe:

create table employees (employeeID number(3), name varchar2(10), department varchar2(5), age number(3), attribute1 varchar2(10), attribute2 varchar2(10), attribute3 varchar2(10));
insert into employees values (1, 'john', 'IT', 22, 'attr1val1', 'attr2val2',  null);
insert into employees values (2, 'jane', 'HR', 32, 'attr1val3', 'attr2val4',  'attr3val5');
insert into employees values (3, 'joe',  'HR', 23, 'attr1val6', 'attr2val7',  'attr3val8');
insert into employees values (4, 'jack', 'IT', 45, 'attr1val9', 'attr2val10', null);

create table attributes (attributeID number(3), department varchar2(10), attribute varchar2(10), meaning varchar2(10));
insert into attributes values (1, 'IT', 'attribute1', 'laptoptype');
insert into attributes values (2, 'IT', 'attribute2', 'networkloc');
insert into attributes values (3, 'HR', 'attribute1', 'location');
insert into attributes values (4, 'HR', 'attribute2', 'position');
insert into attributes values (5, 'HR', 'attribute3', 'allocation');

EMPLOYEEID ATTRIBUTEID DEPARTMENT ATTRIBUTE  MEANING    VALUE
---------- ----------- ---------- ---------- ---------- ----------
         1           1 IT         attribute1 laptoptype attr1val1
         1           2 IT         attribute2 networkloc attr2val2
         2           3 HR         attribute1 location   attr1val3
         2           4 HR         attribute2 position   attr2val4
         2           5 HR         attribute3 allocation attr3val5
         3           3 HR         attribute1 location   attr1val6
         3           4 HR         attribute2 position   attr2val7
         3           5 HR         attribute3 allocation attr3val8
         4           1 IT         attribute1 laptoptype attr1val9
         4           2 IT         attribute2 networkloc attr2val10

Edytuj :Wyjaśnienie

W odpowiedzi użyłem with klauzula tylko po to, aby podzielić rozwiązanie na czytelne kroki. Możesz je przenieść do with klauzula głównego zapytania, jeśli jest to dla Ciebie wygodniejsze. W każdym razie:podzapytanie a odczytuje dane z tabeli attributes i dodaje numer dla wierszy, więc dla każdego działu są one zawsze numerowane od 1. Użyłem numer_wiersza() za to. Podzapytanie e związki (wszystkie) wymagają atrybutów i odpowiednio je numerują. Liczby wygenerowane w obu podzapytaniach są następnie używane w łączeniu głównym:a.department=e.department and a.rn=e.rn .

Alternatywna 1 - jeśli używasz Oracle 11g, możesz użyć unpivot . Zobacz, co jest generowane przez podzapytanie i jak jest połączone z attributes tabela:

with e as (
    select employeeId, name, department, attribute, value from employees
      unpivot (value for attribute in ("ATTRIBUTE1", "ATTRIBUTE2", "ATTRIBUTE3"))  
  )
select e.employeeId, a.attributeid, e.department, a.attribute, 
       a.meaning, e.value 
  from e join attributes a on a.department=e.department 
                          and lower(a.attribute)=lower(e.attribute)
  order by e.employeeId, a.attributeid;

Alternatywna 2 - z hierarchicznym generatorem podzapytań (podzapytanie r ), zrealizowany przez connect by które proste tworzy liczby od 1, 2, 3, które następnie są łączone z employees a odpowiedni atrybut jest dołączony jako wartość w case klauzula. Reszta jest wykonana w podobny sposób jak w oryginalnej odpowiedzi.

with a as (
    select a.*, row_number() over (partition by department order by attributeID) rn
      from attributes a),
  r as (select level rn from dual connect by level<=3),
  e as (
    select employeeId, department, rn,
           case when r.rn = 1 then attribute1
                when r.rn = 2 then attribute2
                when r.rn = 3 then attribute3
           end value
      from employees cross join r
  )
select e.employeeId, a.attributeid, e.department, a.attribute,
       a.meaning, e.value
  from e join a on a.department=e.department and a.rn=e.rn
  order by e.employeeId, a.attributeid

Wszystkie trzy wersje dawały mi ten sam efekt. Testowałem również pierwszą opcję na podobnej tabeli z 100k wierszy i uzyskałem wynik w kilka sekund (dla 5 atrybutów). Przetestuj wszystkie rozwiązania i spróbuj je zrozumieć. Jeśli możesz użyć wersji unpivot, wolałbym to.Przepraszam za opóźnione wyjaśnienie i wszelkie błędy językowe.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy mogę zwrócić wartości do PHP z anonimowego bloku PL/SQL?

  2. BŁĄD w wierszu:PL/SQL:Zignorowano instrukcję SQL. podczas tworzenia/podmieniania treści pakietu

  3. Procedura tworzenia Oracle wywołująca funkcję

  4. Metoda gromadzenia:funkcja LIMIT w bazie danych Oracle

  5. jak używać kaskady w Oracle