MainframeSupports
tip uge 7/2005:

En af de mest irriterende detaljer ved SQL INSERT i DB2 i mange år har været, at man ikke kunne lave en INSERT INTO mytable SELECT * FROM mytable WHERE ... . Det blev der ændret ved i version 7 af DB2. Hurra for det. Desværre er der ikke ret mange, der er klar over det, så derfor dette tip.

Lige så snart man løser et problem, dukker der selvfølgelig nye op. Sådan er det også med kopiering af rækker inden for samme DB2-tabel. Hvis der er et eller flere unikke indexer på tabellen, så skal man selvfølgelig ændre nøgleværdierne. Forestil dig en tabel (mytable) med kolonnerne a, b, c og d, hvor der et et unikt index på kolonnerne a, b. Så kan du lave en ny kopi af en eller flere rækker sådan:

INSERT INTO mytable (a, b, c, d)
SELECT 'NEWVALUE', b, c, d
FROM mytable
WHERE a = 'OLDVALUE'

Det er da ret enkelt og rigtig mange systemer vil kunne drage nytte af ovenstående trick, især når der skal dannes nye rækker i historik-tabeller. Hvis der på en tabel er et unikt index på en kolonne erklæret med typen TIMESTAMP, så er det selvfølgelig nærliggende at benytte CURRENT TIMESTAMP til at give denne kolonne en ny værdi. Men hvis nu SELECT'en returnerer mere end een række, så går det galt med sqlcode -803, da CURRENT TIMESTAMP har samme værdi under hele eksekveringen af et SQL-kald. Av, det var værre. Men her kan du benytte følgende lidt ufine trick (antag, at kolonne b i forrige eksempel er en TIMESTAMP kolonne):

INSERT INTO mytable (a, b, c, d)
SELECT 'NEWVALUE', current timestamp + microsecond(b) microseconds, c, d
FROM mytable
WHERE a = 'OLDVALUE'

Eksemplet tager simpelthen mikrosekunderne i de originale rækker og lægger til current timestamp. Det er selvfølgelig lidt svindel at manipulere med et current timestamp på denne måde, men på den anden side er vi nede i mikrosekunder, så tidsforskydningen bliver ikke særlig stor. Det eneste, der nu kan gå galt, er, hvis to af de originale rækker, der kopieres, har samme antal mikrosekunder. Der er en million at vælge imellem, så sandsynligheden er ikke stor, men til stede (og det er som regel nok til Murphy). Nu mangler IBM altså lige at lave en ny funktion, der kan returnere forskellige timestamp værdier inden for samme SQL-kald.

Det er i øvrigt tankevækkende, at current timestamp for et SQL-kald har samme værdi under hele eksekveringen. Tænk eksempelvis på at en UPDATE, der opdaterer flere millioner rækker og dermed eksekverer i rigtig lang tid, vil tildele samme timestamp til alle opdaterede rækker, også selv om der måske er timers forskel på, hvornår opdateringen af den første række og den sidste række rent faktisk skete.

Forrige danske tip        Last tip in english        Tip oversigten