Ved at bruge IBM Informix Dynamic Server 11.50.FC6 kan jeg bruge denne SQL-sekvens til at få det ønskede resultat:
Opsætning
CREATE TABLE sales
(
id INTEGER NOT NULL,
id_store INTEGER NOT NULL,
date DATE NOT NULL,
total DECIMAL(10,2) NOT NULL
);
INSERT INTO sales VALUES( 1, 1, '2010-01-01', 500.00);
INSERT INTO sales VALUES( 2, 1, '2010-01-02', 185.00);
INSERT INTO sales VALUES( 3, 1, '2010-01-03', 135.00);
INSERT INTO sales VALUES( 4, 1, '2009-01-01', 165.00);
INSERT INTO sales VALUES( 5, 1, '2009-01-02', 175.00);
INSERT INTO sales VALUES( 6, 5, '2010-01-01', 130.00);
INSERT INTO sales VALUES( 7, 5, '2010-01-02', 135.00);
INSERT INTO sales VALUES( 8, 5, '2010-01-03', 130.00);
INSERT INTO sales VALUES( 9, 6, '2010-01-01', 100.00);
INSERT INTO sales VALUES(10, 6, '2010-01-02', 12.00);
INSERT INTO sales VALUES(11, 6, '2010-01-03', 85.00);
INSERT INTO sales VALUES(12, 6, '2009-01-01', 135.00);
INSERT INTO sales VALUES(13, 6, '2009-01-02', 400.00);
INSERT INTO sales VALUES(14, 6, '2009-01-07', 21.00);
INSERT INTO sales VALUES(15, 6, '2009-01-08', 45.00);
INSERT INTO sales VALUES(16, 8, '2009-01-09', 123.00);
INSERT INTO sales VALUES(17, 8, '2009-01-10', 581.00);
Forespørgsel
SELECT *
FROM (SELECT s1.id AS s1id,
NVL(s1.id_store, s2.id_store) AS s1store,
NVL(s1.date, MDY(MONTH(s2.date), DAY(s2.date),
YEAR(s2.date)+1)) AS s1date,
s1.total AS s1total,
s2.id AS s2id,
NVL(s2.id_store, s1.id_store) AS s2store,
NVL(s2.date, MDY(MONTH(s1.date), DAY(s1.date),
YEAR(s1.date)-1)) AS s2date,
s2.total AS s2total
FROM sales AS s1 FULL JOIN sales AS s2
ON s1.id_store = s2.id_store
AND s1.date BETWEEN '2010-01-01' AND '2010-01-10'
AND s2.date BETWEEN '2009-01-01' AND '2009-01-10'
AND DAY(s1.date) = DAY(s2.date)
AND MONTH(s1.date) = MONTH(s2.date)
) AS s3
WHERE s1_date BETWEEN '2010-01-01' AND '2010-01-10'
AND s2_date BETWEEN '2009-01-01' AND '2009-01-10'
ORDER BY s1_id_store ASC, s1_date ASC;
Resultat
s1id s1store s1date s1total s2id s2store s2date s2total
1 1 2010-01-01 500.00 4 1 2009-01-01 165.00
2 1 2010-01-02 185.00 5 1 2009-01-02 175.00
3 1 2010-01-03 135.00 1 2009-01-03
6 5 2010-01-01 130.00 5 2009-01-01
7 5 2010-01-02 135.00 5 2009-01-02
8 5 2010-01-03 130.00 5 2009-01-03
9 6 2010-01-01 100.00 12 6 2009-01-01 135.00
10 6 2010-01-02 12.00 13 6 2009-01-02 400.00
11 6 2010-01-03 85.00 6 2009-01-03
6 2010-01-07 14 6 2009-01-07 21.00
6 2010-01-08 15 6 2009-01-08 45.00
8 2010-01-09 16 8 2009-01-09 123.00
8 2010-01-10 17 8 2009-01-10 581.00
Forklaring
Det krævede en del eksperimenter for at få det 'rigtige'. Informix har en DATE-konstruktørfunktion MDY(), som tager tre heltalsargumenter:måneden, dagen og året (navnet er mnemonisk). Den har også tre analysefunktioner:DAY(), MONTH() og YEAR() som returnerer dagen, måneden og året for datoargumentet. Den indre forespørgsel med FULL JOIN giver dig resultaterne med nuller på både venstre og højre side. 5-delt kriteriet i ON-klausulen synes at være nødvendigt; ellers skal kriterierne i den ydre forespørgsel være mere komplekse og forvirrende - hvis det overhovedet kan fås til at virke. Så sikrer kriterierne i det ydre udvalg, at de rigtige data bliver valgt. En fordel ved NVL()-udtrykkene i den indre forespørgsel er, at butiks-id-kolonnerne både er de samme og ikke null, og ingen af datokolonnerne er null, så rækkefølgen efter klausul kan være enklere - på butiks-id og begge datokolonne.
I Informix ville det også være muligt at omarbejde datoudtrykkene som:
NVL(s1.date, s2.date + 1 UNITS YEAR)
NVL(s2.date, s1.date - 1 UNITS YEAR)
Der foregår faktisk flere typekonverteringer bag kulisserne med den notation, men det giver dig det samme resultat, og den ekstra beregning er nok ikke så væsentlig.
Der er også en fejl i at vente i Informix; du kan ikke tilføje eller trække 1 år til eller fra nogen 29. februar - fordi der ikke er 29. februar i det følgende eller foregående år. Du skal være forsigtig med dine data; hvis du ikke er det, kan du ende med at sammenligne dataene for 2008-02-29 med 2009-02-28 (såvel som at sammenligne dataene for 2008-02-28 med 2009-02-28). Der er en proces kaldet 'dobbelt bogføring', men det er ikke det, der menes med det, og dine beregninger kan blive forvirrede, hvis '2008-02-29 plus 1 år' er 2009-02-28. Informix genererer en fejl; det er ikke meget mere nyttigt. Du kan muligvis kode en lagret procedure for at returnere NULL for 2008-02-29 plus 1 år, da der ikke er nogen dato at sammenligne salget med.
Du burde være i stand til at tilpasse dato-aritmetikken til MySQL forholdsvis let; resten af koden behøver ikke at ændres.