MainframeSupports
tip uge 15/2003:

Med fremkomsten af outer joins i DB2 version 4 lærte mange af os funktionen COALESCE at kende. Før version 4 havde den heddet VALUE, men COALESCE er ANSI standard navnet for funktionen. Jeg bruger fortsat kun VALUE. Og hvad er det nu lige VALUE gør. Jo, hvis det første argument er NULL, så returnerer VALUE værdien af det andet argument. Hvis det også er NULL, så returneres værdien af det tredie argument og så fremdeles. Hvis alle argmenter er NULL, så returneres NULL. I version 6 er afarten IFNULL kommet til. Det er VALUE begrænset til to argumenter.

Der er vel ingen tvivl hos dig om det praktiske i at benytte VALUE til at oversætte en NULL værdi til noget mere sigende. Hvad der til gengæld nok er værd at vide, er hvornår en værdi er NULL. Faktisk returnerer DB2 værdien NULL i overraskende mange tilfælde ud over i outer joins. Eksempelvis fejler et SQL-kald ikke ved division med 0, det returnerer i stedet værdien NULL.

Mange funktioner returnerer værdien NULL i stedet for at fejle. Især er det godt at vide, at MIN, MAX, AVG og SUM returnerer NULL, hvis de skal beregne resultatet på baggrund af 0 rækker. SUM og AVG burde faktisk returnere 0 i dette tilfælde, men du kan kompensere med en VALUE(xxx(sum_kolonne), 0), hvor xxx er AVG eller SUM.

Et andet trick er selvfølgelig at benytte VALUE i konverteringer. Eksempelvis har mange installationer fra gammel tid anvendt alt muligt andet end lige DATE definerede kolonner til at gemme datoer i. De fleste dato-funktioner i DB2 returnerer NULL, hvis man fordrer dem med en invalid dato (som i øvrigt kan angives på mange måder), og så kan man med VALUE(dato-funktion(gammeldags-dato), 'YYYY-MM-DD') returnere en værdi alligevel og du kan endda selv vælge, hvad YYYY, MM og DD skal være.

Endnu snedigere er brugen af VALUE sammen med en subselect. Forestil dig en historik tabel med kolonne keyvalue og kolonne keydate og en masse andre kolonner. Du skal nu finde alle de rækker, der er eller har været gældende siden en given skæringsdato. Den simple løsning er, at sige WHERE keydate >= skæringsdato, men den medtager ikke de rækker, der var gældende på skæringsdatoen. Altså må du kaste dig ud i noget med en subselect:

SELECT * FROM hist_table o
WHERE keydate >=
( SELECT MAX(keydate) FROM hist_table
  WHERE keydate <= :skæringdato
    AND keyvalue = o.keyvalue
)

Dette SQL-kald udtrækker de rækker, der er gældende på skæringsdatoen sammen med alle de rækker med en keydate efter skæringsdatoen. Til gengæld mangler alle de rækker, hvor der for en given keyvalue ikke findes en eneste række med en keydate <= skæringsdatoen. Nu kan VALUE hjælpe os. Subselect'en ændres til SELECT VALUE(MAX(keydate), '0001-01-01') med resten uændret. Nu kommer de manglende rækker med.

Når du har øvet dig lidt med VALUE og fundet ud af alle de mange steder, hvor DB2 returnerer NULL, så vil det gå op for dig, hvilken fantastisk stærk funktion VALUE egentlig er. Første vigtige skridt er at flytte brugen af VALUE fra SELECT listen ned i WHERE delen. Så er der uanede muligheder for at løse komplicerede problemstillinger på enkle måder.

Forrige danske tip        Last tip in english        Tip oversigten