sql >> Databasteknik >  >> RDS >> Mysql

Jämför två datumintervall inom samma tabell

Med IBM Informix Dynamic Server 11.50.FC6 kan jag använda den här SQL-sekvensen för att få det resultat du behöver:

Inställningar

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);

Fråga

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

Förklaring

Det krävdes en hel del experiment för att få det här "rätt". Informix har en DATE-konstruktorfunktion MDY() som tar tre heltalsargument:månad, dag och år (namnet är mnemonisk). Den har också tre analysfunktioner:DAY(), MONTH() och YEAR() som returnerar dagen, månaden och året för datumargumentet. Den inre frågan med FULL JOIN ger dig resultaten med nollor på både vänster och höger sida. Det 5-delade kriteriet i ON-klausulen verkar vara nödvändigt; annars måste kriterierna i den yttre frågan vara mer komplexa och förvirrande - om det överhuvudtaget kan fås att fungera. Då säkerställer kriterierna i det yttre urvalet att rätt data väljs. En fördel med NVL()-uttrycken i den inre frågan är att butiks-ID-kolumnerna både är desamma och inte null och att ingen av datumkolumnerna är null, så order by-satsen kan vara enklare - på butiks-ID och endera datumkolumnen.

I Informix skulle det också vara möjligt att omarbeta datumuttrycken som:

NVL(s1.date, s2.date + 1 UNITS YEAR)
NVL(s2.date, s1.date - 1 UNITS YEAR)

Det pågår faktiskt flera typkonverteringar bakom kulisserna med den notationen, men det ger dig samma resultat och den extra beräkningen är förmodligen inte så signifikant.

Det finns också ett fel i väntan i Informix; du kan inte lägga till eller subtrahera 1 år till eller från någon 29 februari - eftersom det inte finns någon 29 februari följande eller föregående år. Du skulle behöva vara försiktig med dina data; om du inte är det kan du sluta med att jämföra uppgifterna för 2008-02-29 med 2009-02-28 (liksom att jämföra uppgifterna för 2008-02-28 med 2009-02-28). Det finns en process som kallas "dubbel bokföring", men det är inte vad som menas med det, och dina beräkningar kan bli förvirrade om "2008-02-29 plus 1 år" är 2009-02-28. Informix genererar ett fel; det är inte så mycket mer användbart. Du kanske kodar en lagrad procedur för att returnera NULL för 2008-02-29 plus 1 år eftersom det inte finns något datum att jämföra försäljningen med.

Du bör kunna anpassa datumräkningen till MySQL ganska enkelt; resten av koden behöver inte ändras.



  1. Flerskiktskommentarsvar:Display och lagring

  2. Hur kan jag infoga binära fildata i ett binärt SQL-fält med en enkel infogningssats?

  3. mysql som fråga exkludera siffror

  4. Hur man visar status och systemvariabler i MySQL Workbench med hjälp av GUI