sql >> Database >  >> RDS >> Mysql

Twee perioden binnen dezelfde tabel vergelijken

Met IBM Informix Dynamic Server 11.50.FC6 kan ik deze SQL-reeks gebruiken om het gewenste resultaat te krijgen:

Instellen

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

Zoekopdracht

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;

Resultaat

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

Uitleg

Het vergde behoorlijk wat experimenten om dit 'goed' te krijgen. Informix heeft een DATE-constructorfunctie MDY() die drie integer-argumenten nodig heeft:de maand, de dag en het jaar (de naam is mnemonic). Het heeft ook drie analysefuncties:DAY(), MONTH() en YEAR() die de dag, de maand en het jaar van het datumargument retourneren. De innerlijke query met de FULL JOIN geeft je de resultaten met nulls aan zowel de linker- als de rechterkant. Het 5-delige criterium in de ON-clausule lijkt noodzakelijk; anders moeten de criteria in de buitenste query complexer en verwarrender zijn - als het al mogelijk is om te werken. Dan zorgen de criteria in de buitenste selectie ervoor dat de juiste data wordt gekozen. Een voordeel van de NVL()-expressies in de binnenste query is dat de kolommen voor winkel-ID's hetzelfde zijn en niet null en dat geen van beide datumkolommen null is, dus de clausule op volgorde kan eenvoudiger zijn - op winkel-ID en beide datumkolommen.

In Informix zou het ook mogelijk zijn om de datum-uitdrukkingen te herwerken als:

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

Er zijn eigenlijk meerdere typeconversies gaande achter de schermen met die notatie, maar het geeft je hetzelfde resultaat en de extra berekening is waarschijnlijk niet zo belangrijk.

Er is ook een storing in het wachten in Informix; u kunt 1 jaar niet optellen bij of aftrekken van 29 februari - omdat er geen 29 februari is in het volgende of voorgaande jaar. Je zou voorzichtig moeten zijn met je gegevens; als je dat niet bent, zou je de gegevens voor 29-02-2008 kunnen vergelijken met 28-02-2009 (en de gegevens voor 28-02-2008 met 28-02-2009). Er is een proces dat 'boekhouden met dubbele boeking' wordt genoemd, maar dit is niet wat ermee wordt bedoeld, en uw berekeningen kunnen in de war raken als '29-02-2008 plus 1 jaar' 28-02-2009 is. Informix genereert een fout; dat is niet veel handiger. U kunt waarschijnlijk een opgeslagen procedure coderen om NULL te retourneren voor 29-02-2008 plus 1 jaar, aangezien er geen datum is om de verkoop mee te vergelijken.

Je zou in staat moeten zijn om de datumberekening vrij eenvoudig aan te passen aan MySQL; de rest van de code hoeft niet te worden gewijzigd.



  1. Verschil tussen TRIM() en TRIM_ORACLE() in MariaDB

  2. Vind overlap van datumbereiken binnen dezelfde tabel, voor specifieke gebruiker MySQL

  3. MySQL - hoe lang duurt het om een ​​index te maken?

  4. Hoe hebben Android-apps toegang tot MySQL?