Mysql
 sql >> база данни >  >> RDS >> Mysql

Сравняване на два периода от време в една и съща таблица

Използвайки IBM Informix Dynamic Server 11.50.FC6, мога да използвам тази SQL последователност, за да получа желания резултат:

Настройка

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

Запитване

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;

Резултат

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

Обяснение

Отне доста експерименти, за да се получи това „правилно“. Informix има функция за конструктор DATE MDY(), която приема три целочислени аргумента:месец, ден и година (името е мнемонично). Той също така има три функции за анализ:DAY(), MONTH() и YEAR(), които връщат деня, месеца и годината на аргумента за дата. Вътрешната заявка с FULL JOIN ви дава резултатите с нулеви стойности от лявата и дясната страна. Критерият от 5 части в клаузата ON изглежда е необходим; в противен случай критериите във външната заявка трябва да са по-сложни и объркващи - ако изобщо може да се накара да работи. Тогава критериите във външния подбор гарантират, че са избрани правилните данни. Едно предимство на изразите NVL() във вътрешната заявка е, че колоните с идентификационен номер на магазина са еднакви и не са нулеви и нито една колона за дата не е нула, така че подреждането по клауза може да бъде по-просто - по идентификатора на магазина и всяка колона за дата.

В Informix също би било възможно да се преработят изразите за дата като:

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

Всъщност има множество преобразувания на типове, които се случват зад кулисите с тази нотация, но това ви дава същия резултат и допълнителното изчисление вероятно не е толкова важно.

Има и проблем в чакането в Informix; не можете да добавяте или изваждате 1 година към или от който и да е 29 февруари - защото няма 29 февруари в следващата или предишната година. Ще трябва да внимавате с данните си; ако не сте, бихте могли да сравните данните за 2008-02-29 с 2009-02-28 (както и да сравните данните за 2008-02-28 с 2009-02-28). Има процес, наречен „счетоводство с двойно вписване“, но това не се има предвид под него и вашите изчисления могат да бъдат объркани, ако „2008-02-29 плюс 1 година“ е 2009-02-28. Informix генерира грешка; това не е много по-полезно. Може да кодирате съхранена процедура, вероятно, за да върне NULL за 2008-02-29 плюс 1 година, тъй като няма дата, с която да се сравняват продажбите й.

Трябва да можете сравнително лесно да адаптирате аритметиката за дати към MySQL; останалата част от кода не е необходимо да се променя.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. предайте sql файл на nodejs за изпълнение като цяло

  2. Какъв тип данни в колона трябва да използвам за съхранение на големи количества текст или html

  3. Mysql INSTR подобна операция в mongodb

  4. MySQL IF условие в изчислено поле

  5. Мога ли да настроя филтрирана репликация на база данни със звезда?