Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Vergleichen von zwei Datumsbereichen innerhalb derselben Tabelle

Unter Verwendung von IBM Informix Dynamic Server 11.50.FC6 kann ich diese SQL-Sequenz verwenden, um das gewünschte Ergebnis zu erhalten:

Einrichtung

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

Abfrage

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;

Ergebnis

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

Erklärung

Es bedurfte einiger Experimente, um dies „richtig“ hinzubekommen. Informix verfügt über eine DATE-Konstruktorfunktion MDY(), die drei ganzzahlige Argumente akzeptiert:den Monat, den Tag und das Jahr (der Name ist mnemonisch). Es hat auch drei Analysefunktionen:DAY(), MONTH() und YEAR(), die Tag, Monat und Jahr des Datumsarguments zurückgeben. Die innere Abfrage mit dem FULL JOIN gibt Ihnen die Ergebnisse mit Nullen auf der linken und rechten Seite. Das 5-teilige Kriterium in der ON-Klausel scheint notwendig zu sein; Andernfalls müssen die Kriterien in der äußeren Abfrage komplexer und verwirrender sein - wenn es überhaupt funktioniert. Dann sorgen die Kriterien in der äußeren Auswahl dafür, dass die richtigen Daten ausgewählt werden. Ein Vorteil der NVL()-Ausdrücke in der inneren Abfrage besteht darin, dass die Geschäfts-ID-Spalten beide gleich und nicht null sind und keine der Datumsspalten null ist, sodass die Order-by-Klausel einfacher sein kann – auf Geschäfts-ID und einer der beiden Datumsspalten.

In Informix wäre es auch möglich, die Datumsausdrücke wie folgt umzuarbeiten:

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

Hinter den Kulissen finden bei dieser Notation tatsächlich mehrere Typkonvertierungen statt, aber Sie erhalten das gleiche Ergebnis, und die zusätzliche Berechnung ist wahrscheinlich nicht so wichtig.

Es gibt auch einen Fehler beim Warten in Informix; Sie können zu keinem 29. Februar 1 Jahr addieren oder subtrahieren, da es im folgenden oder vorherigen Jahr keinen 29. Februar gibt. Sie müssten mit Ihren Daten vorsichtig sein; Wenn nicht, könnten Sie am Ende die Daten für 2008-02-29 mit 2009-02-28 vergleichen (sowie die Daten für 2008-02-28 mit 2009-02-28). Es gibt einen Prozess namens „doppelte Buchführung“, aber das ist nicht gemeint, und Ihre Berechnungen könnten verwirrt sein, wenn „2008-02-29 plus 1 Jahr“ 2009-02-28 ist. Informix generiert einen Fehler; das ist nicht sehr viel hilfreicher. Sie könnten wahrscheinlich eine gespeicherte Prozedur so programmieren, dass sie NULL für den 29.02.2008 plus 1 Jahr zurückgibt, da es kein Datum gibt, mit dem die Verkäufe verglichen werden können.

Sie sollten in der Lage sein, die Datumsarithmetik ziemlich einfach an MySQL anzupassen; der Rest des Codes muss nicht geändert werden.