sql >> Database >  >> RDS >> Oracle

Hoe horizontale waarden van een tabel te binden aan verticale waarden van een andere tabel in de Oracle-database

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

Testgegevens en output:

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

Bewerken :Uitleg

Als antwoord gebruikte ik with clausule alleen om de oplossing in leesbare stappen te verdelen. Je kunt ze verplaatsen naar from clausule van de hoofdquery als u dit prettiger vindt. Hoe dan ook:subquery a leest gegevens uit tabel attributes en voegt nummer toe voor rijen, dus voor elke afdeling zijn ze altijd genummerd vanaf 1. Ik gebruikte row_number() daarom. Subquery e vakbonden (alle) vereiste attributen en nummert ze dienovereenkomstig. Getallen die in beide subquery's worden gegenereerd, worden vervolgens gebruikt in de hoofdjoin:a.department=e.department and a.rn=e.rn .

Alternatief 1 - als u Oracle 11g gebruikt, kunt u de unpivot gebruiken . Bekijk wat wordt gegenereerd door subquery's en hoe deze wordt samengevoegd met attributes tafel:

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;

Alternatief 2 - met hiërarchische subquerygenerator (subquery r ), gerealiseerd door connect by die eenvoudig getallen maakt van 1, 2, 3 die vervolgens worden samengevoegd met employees en het juiste attribuut is toegevoegd als waarde in case clausule. Rust wordt op dezelfde manier gemaakt als in het oorspronkelijke antwoord.

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 drie de versies gaven me dezelfde output. Ik heb ook de eerste optie getest op een vergelijkbare tabel met 100k rijen en krijg binnen enkele seconden uitvoer (voor 5 attributen). Test alle oplossingen en probeer ze te begrijpen. Als je de versie zonder draaien kunt gebruiken, zou ik hier de voorkeur aan geven. Sorry voor de vertraagde uitleg en eventuele taalfouten.



  1. Hoe te verwijderen uit meerdere tabellen in MySQL?

  2. Krijg de volgende foutmelding - Geen geschikt stuurprogramma gevonden voor jdbc:postgresql://localhost:5432/testDBMS

  3. De hoogste resultaten behalen in een JOIN

  4. ORA-01031:onvoldoende privileges bij het selecteren van weergave