sql >> Databáze >  >> RDS >> Mysql

Porovnání dvou období v rámci stejné tabulky

Pomocí IBM Informix Dynamic Server 11.50.FC6 mohu použít tuto sekvenci SQL k získání požadovaného výsledku:

Nastavení

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

Dotaz

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;

Výsledek

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

Vysvětlení

Aby to bylo „správné“, vyžadovalo to značné množství experimentů. Informix má funkci konstruktoru DATE MDY(), která přebírá tři celočíselné argumenty:měsíc, den a rok (název je mnemotechnická pomůcka). Má také tři analytické funkce:DAY(), MONTH() a YEAR(), které vracejí den, měsíc a rok argumentu data. Vnitřní dotaz s FULL JOIN vám poskytne výsledky s nulami na levé i pravé straně. Zdá se, že 5dílné kritérium v ​​klauzuli ON je nezbytné; v opačném případě musí být kritéria ve vnějším dotazu složitější a matoucí – pokud je vůbec možné zajistit. Kritéria ve vnějším výběru pak zajistí výběr správných dat. Jednou z výhod výrazů NVL() ve vnitřním dotazu je to, že sloupce ID obchodu jsou stejné a nejsou prázdné a žádný sloupec data není prázdný, takže řazení podle klauzule může být jednodušší – na ID obchodu a na kterémkoli sloupci data.

V Informixu by také bylo možné přepracovat výrazy data jako:

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

Ve skutečnosti v zákulisí s tímto zápisem probíhá několik převodů typů, ale dává vám stejný výsledek a další výpočet pravděpodobně není tak významný.

V Informixu je také chyba v čekání; nemůžete přičíst ani odečíst 1 rok od žádného 29. února – protože v následujícím nebo předchozím roce není žádný 29. únor. Měli byste být opatrní se svými údaji; pokud nejste, můžete skončit srovnáním údajů za rok 2008-02-29 s 2009-02-28 (stejně jako srovnáním údajů za rok 2008-02-28 s 2009-02-28). Existuje proces zvaný 'podvojné účetnictví', ale to není to, co se tím myslí, a vaše výpočty by mohly být zmatené, pokud '2008-02-29 plus 1 rok' je 2009-02-28. Informix generuje chybu; to není o moc užitečnější. Pravděpodobně můžete nakódovat uloženou proceduru tak, aby vrátila hodnotu NULL pro 2008-02-29 plus 1 rok, protože neexistuje žádné datum, se kterým by se dal porovnat její prodeje.

Měli byste být schopni poměrně snadno přizpůsobit aritmetiku data MySQL; zbytek kódu není třeba měnit.



  1. Líné načítání jednoho sloupce (atribut třídy) pomocí režimu spánku

  2. Jak fungují indexy MySQL?

  3. Vrácení informací o sloupci pro uloženou proceduru na serveru SQL Server:sp_sproc_columns

  4. Gem install mysql selhal