MainframeSupports
tip uge 23/2012:

Jeg skrev for lidt over tre år siden et tip om, hvordan du kan splitte en kolonne over flere rækker. Nu er det blevet tid til at skrive om, hvordan du samler information fra flere rækker i een række. Nu tænker du nok, at det er jo bare at bruge GROUP BY, og jeg vil gerne indrømme, at du kan komme langt med GROUP BY, især hvis du kombinerer den med CASE, men det kan jeg vende tilbage til en anden gang.

Min ide går i stedet ud på at bruge LEFT JOIN til formålet. Bare for at illustrere princippet vil jeg tage udgangspunkt i et eksempel, du kan udføre på enhver DB2 for z/OS. Opgaven går ud på at vise een række pr. tabel i system-kataloget, som indeholder tabelnavnet og kolonnerne i den primære nøgle. Det kan løses sådan her:

select substr(t.name, 1, 18) table
     , char(strip(c1.name) !! ' '
     !! strip(value(c2.name, '')) !! ' '
     !! strip(value(c3.name, '')) !! ' '
     !! strip(value(c4.name, '')) !! ' '
     !! strip(value(c5.name, '')) !! ' ') primary_key_columns
from sysibm.systables t
     left join sysibm.syscolumns c1 on c1.keyseq = 1
     and c1.tbname = t.name and c1.tbcreator = t.creator
     left join sysibm.syscolumns c2 on c2.keyseq = 2
     and c2.tbname = t.name and c2.tbcreator = t.creator
     left join sysibm.syscolumns c3 on c3.keyseq = 3
     and c3.tbname = t.name and c3.tbcreator = t.creator
     left join sysibm.syscolumns c4 on c4.keyseq = 4
     and c4.tbname = t.name and c4.tbcreator = t.creator
     left join sysibm.syscolumns c5 on c5.keyseq = 5
     and c5.tbname = t.name and c5.tbcreator = t.creator
where t.creator = 'SYSIBM'
  and t.name like 'SYS%'
  and t.type = 'T'
  and t.keycolumns > 0
order by t.name

Netop fordi antallet af kolonner i den primære nøgle ikke kendes i forvejen er en LEFT JOIN oplagt til at løse opgaven. For at fremgangsmåden kan benyttes i andre situationer skal tabellen med de rækker, der skal klappes sammen til een række, have en kolonne, der indentificerer den enkelte række. I eksemplet er det keyseq kolonnen. Derudover skal du i selve SQL-teksten være i stand til at identificere den enkelte række. I eksemplet sker det med konstanterne 1, 2, 3, 4 og 5. I eksemplet kan "on c2.keyseq = 2" erstattes med udtrykket "on c2.keyseq = c1.keyseq + 1" og så fremdeles. Det vigtigste er, at hver enkelt række kan identificeres enten med en konstant eller et udtryk.

Fremgangsmåden i ovenstående eksempel har den store ulempe, at den begrænser antallet af rækker, der kan klappes sammen. Det er antallet af LEFT JOINs, der bestemmer, hvor mange rækker, der maksimalt kan klappes sammen. Det kan derfor være en god ide at markere om der er rækker, der ikke er blevet taget med. Det kan i ovenstående eksempel gøres med en ekstra left join, og så concatenere udtrykket CASE C6.KEYSEQ WHEN 6 THEN '>>' ELSE '' END på.

Enkelte af mine trofaste læsere vil have bemærket, at jeg ofte har udtrykt begejstring for rekursive løsninger. Opgaven her lægger i den grad op til en rekursiv løsning, men indtil jeg selv får behov for den eller får overskud til at udtænke den selv, så må du selv til at tænke kreativt. Hvis du når at lave den inden du læser om den på min hjemmeside, så send mig en kopi, så vil jeg publicere den, hvis du har lyst til det.

Forrige danske tip        Last tip in english        Tip oversigten