Mysql 比较同一表中的两个日期范围

Mysql 比较同一表中的两个日期范围,mysql,null,date,compare,range,Mysql,Null,Date,Compare,Range,我有一个表,每个商店的销售额如下: SQL> select * from sales; ID ID_STORE DATE TOTAL ---------- -------- ---------- ------------------------------- 1 1 2010-01-01 500.00 2 1 2010-01-02 185.00 3 1

我有一个表,每个商店的销售额如下:

SQL> select * from sales;

        ID ID_STORE DATE       TOTAL
---------- -------- ---------- -------------------------------
         1        1 2010-01-01    500.00
         2        1 2010-01-02    185.00
         3        1 2010-01-03    135.00
         4        1 2009-01-01    165.00
         5        1 2009-01-02    175.00
         6        5 2010-01-01    130.00
         7        5 2010-01-02    135.00
         8        5 2010-01-03    130.00
         9        6 2010-01-01    100.00
         10       6 2010-01-02     12.00
         11       6 2010-01-03     85.00
         12       6 2009-01-01    135.00
         13       6 2009-01-02    400.00
         14       6 2009-01-07     21.00
         15       6 2009-01-08     45.00
         16       8 2009-01-09    123.00
         17       8 2009-01-10    581.00

17 rows selected.
我需要做的是比较该表中的两个日期范围。假设我需要知道2009年1月1日至2009年1月10日与2010年1月1日至2010年1月10日之间的销售额差异

我想构建一个返回如下内容的查询:

ID_STORE_A DATE_A     TOTAL_A   ID_STORE_B DATE_B     TOTAL_B
---------- ---------- --------- ---------- ---------- -------------------
         1 2010-01-01    500.00          1 2009-01-01    165.00
         1 2010-01-02    185.00          1 2009-01-02    175.00
         1 2010-01-03    135.00          1 NULL          NULL

         5 2010-01-01    130.00          5 NULL          NULL
         5 2010-01-02    135.00          5 NULL          NULL
         5 2010-01-03    130.00          5 NULL          NULL

         6 2010-01-01    100.00          6 2009-01-01    135.00
         6 2010-01-02     12.00          6 2009-01-02    400.00
         6 2010-01-03     85.00          6 NULL          NULL
         6 NULL          NULL            6 2009-01-07     21.00
         6 NULL          NULL            6 2009-01-08     45.00
         6 NULL          NULL            8 2009-01-09    123.00
         6 NULL          NULL            8 2009-01-10    581.00
因此,即使某个范围内没有销售,也应该用NULL填充空白

到目前为止,我已经提出了这个快速查询,但我认为从sales到sales2的“日期”有时在每一行都是不同的:

SELECT sales.*, sales2.*
  FROM sales
  LEFT JOIN sales AS sales2 
    ON (sales.id_store=sales2.id_store)
 WHERE sales.date >= '2010-01-01' 
   AND sales.date <= '2010-01-10' 
   AND sales2.date >= '2009-01-01' 
   AND sales2.date <= '2009-01-10' 
ORDER BY sales.id_store ASC, sales.date ASC, sales2.date ASC
选择sales.*,sales2*
来自销售
左作为销售人员加入销售2
打开(sales.id\u store=sales2.id\u store)
其中sales.date>=“2010-01-01”
和sales.date='2009-01-01'

和sales2.date我认为问题在于你的加入条件。我还没试过,但我想你可以试一下

... ON (    sales.id_store = sales2.id_store 
        AND sales.date = ADDDATE(sales2.date, INTERVAL 1 YEAR) 
        ...
       )

使用IBM Informix Dynamic Server 11.50.FC6,我可以使用以下SQL序列获得您所需的结果:

安装程序 查询 结果 解释 这需要大量的实验才能“正确”。Informix有一个日期构造函数MDY(),它接受三个整数参数:月、日和年(名称是助记符)。它还有三个分析函数:DAY()、MONTH()和YEAR(),它们返回date参数的日期、月份和年份。带有完全联接的内部查询将提供左右两侧都为null的结果。ON条款中的5部分标准似乎是必要的;否则,外部查询中的条件必须更加复杂和混乱——如果它能够工作的话。然后外部选择中的标准确保选择了正确的数据。内部查询中的NVL()表达式的一个优点是存储ID列都相同且不为null,日期列也不为null,因此order by子句可以更简单—在存储ID和任一日期列上

在Informix中,还可以将日期表达式修改为:

NVL(s1.date, s2.date + 1 UNITS YEAR)
NVL(s2.date, s1.date - 1 UNITS YEAR)
实际上,使用这种符号在幕后进行了多个类型转换,但它给出了相同的结果,额外的计算可能并不那么重要

Informix中的等待也有一个小故障;您不能在任何2月29日加上或减去1年,因为下一年或上一年没有2月29日。你需要小心你的数据;如果你没有,你最终可能会比较2008-02-29和2009-02-28的数据(以及比较2008-02-28和2009-02-28的数据)。有一个过程叫做“复式簿记”,但这不是它的意思,如果“2008-02-29加1年”是2009-02-28,你的计算可能会混淆。Informix生成一个错误;这并没有多大帮助。您可能会编写一个存储过程,在2008-02-29加上1年后返回NULL,因为没有任何日期可以比较它的销售额


您应该能够相当容易地将日期算法适应MySQL;代码的其余部分不需要更改。

您需要了解“分组依据”和子查询。如果两侧都为null,则可能需要完全外部联接,而不是左外部联接或右外部联接。
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
NVL(s1.date, s2.date + 1 UNITS YEAR)
NVL(s2.date, s1.date - 1 UNITS YEAR)