使用 IBM Informix Dynamic Server 11.50.FC6,我可以使用此 SQL 序列来获取您需要的结果:
Setup
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);
Query
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;
Result
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 的内部查询为您提供左侧和右侧均包含空值的结果。 ON子句中的5部分标准似乎是必要的;否则,外部查询中的条件必须更加复杂和混乱 - 如果它可以正常工作的话。然后,外部选择中的标准可确保选择正确的数据。内部查询中 NVL() 表达式的一个优点是商店 ID 列相同且不为空,并且日期列都不为空,因此 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;其余代码不需要更改。