sql >> Databasteknik >  >> RDS >> Oracle

Hur man binder horisontella värden för en tabell till vertikala värden för en annan tabell i Oracle-databasen

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

Testa data och utdata:

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

Redigera :Förklaring

Som svar använde jag with klausul bara för att dela upp lösningen i läsbara steg. Du kan flytta dem till from klausul i huvudfrågan om det är bekvämare för dig. Hur som helst:underfråga a läser data från tabell attributes och lägger till nummer för rader, så för varje avdelning är de alltid numrerade från 1. Jag använde radnummer() för det. Underfråga e fackföreningar (alla) krävde attribut och nummer i enlighet därmed. Siffror som genereras i båda underfrågorna används sedan i huvudkopplingen:a.department=e.department and a.rn=e.rn .

Alternativ 1 - om du använder Oracle 11g kan du använda unpivot . Se vad som genereras av underfrågan och hur den sammanfogas med attributes tabell:

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;

Alternativ 2 - med hierarkisk subquery generator (subquery r ), realiserat av connect by vilken enkel skapar nummer från 1, 2, 3 som sedan sammanfogas med employees och korrekt attribut bifogas som värde i case klausul. Vila görs på liknande sätt som i originalsvaret.

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

Alla tre versionerna gav mig samma resultat. Jag testade också det första alternativet på en liknande tabell med 100k rader och få utdata på några sekunder (för 5 attribut). Testa alla lösningar och försök förstå dem. Om du kan använda unpivot-versionen skulle jag föredra detta. Ursäkta försenad förklaring och eventuella språkfel.



  1. Relation mellan katalog, schema, användare och databasinstans

  2. Laravel kan inte ansluta till databasen - Migrationer - Fel 2002

  3. SQL konvertera 'DDMMYY' till datetime

  4. MySQL-fråga för att få räkning per timme