Oracle
 sql >> Datenbank >  >> RDS >> Oracle

So binden Sie horizontale Werte einer Tabelle an vertikale Werte einer anderen Tabelle in der Oracle-Datenbank

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

Testdaten und Ausgabe:

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

Bearbeiten :Erklärung

Als Antwort habe ich mit Klausel nur um die Lösung in lesbare Schritte zu unterteilen. Sie können sie nach from verschieben Klausel der Hauptabfrage, wenn es für Sie bequemer ist. Trotzdem:Unterabfrage a liest Daten aus der Tabelle attributes und fügt Nummer für Zeilen hinzu, sodass sie für jede Abteilung immer von 1 an nummeriert sind /functions137.htm">Zeilennummer() dafür. Unterabfrage e Gewerkschaften (alle) benötigten Attribute und nummerieren sie entsprechend. Die in beiden Unterabfragen generierten Nummern werden dann im Hauptjoin verwendet:a.department=e.department and a.rn=e.rn .

Alternative 1 - Wenn Sie Oracle 11g verwenden, können Sie den unpivot verwenden . Sehen Sie, was von einer Unterabfrage generiert wird und wie sie mit attributes verknüpft wird Tabelle:

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;

Alternative 2 - mit hierarchischem Subquery-Generator (subquery r ), realisiert durch Verbinden durch was einfach Zahlen aus 1, 2, 3 erzeugt, die als nächstes mit Mitarbeitern verbunden werden und das richtige Attribut wird als Wert in case angehängt Klausel. Der Rest erfolgt auf ähnliche Weise wie in der ursprünglichen Antwort.

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

Alle drei Versionen gaben mir die gleiche Ausgabe. Ich habe auch die erste Option auf einer ähnlichen Tabelle mit 100.000 Zeilen getestet und die Ausgabe in wenigen Sekunden erhalten (für 5 Attribute). Bitte testen Sie alle Lösungen und versuchen Sie, sie zu verstehen. Wenn Sie die unpivot-Version verwenden können, würde ich diese bevorzugen. Entschuldigen Sie die verspätete Erklärung und etwaige Sprachfehler.