您可以使用此单语句解决方案:
SELECT a.date date1,
b.date date2,
DATEDIFF(b.date, a.date) ddiff
FROM (
SELECT @a_rn:=@a_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @a_rn:=0) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
) a
JOIN (
SELECT @b_rn:=@b_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @b_rn:=-1) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
) b ON a.ascrank = b.ascrank
ORDER BY ddiff DESC
LIMIT 1
查询细分
给定这个示例数据集:
CREATE TABLE tbl (
date DATE
);
INSERT INTO tbl VALUES
('1950-05-01'),
('1965-08-10'),
('1990-12-30'),
('1990-12-29'),
('2012-09-03');
我们希望找到两个连续日期之间的最大差异(意思是,给定按升序排列的日期,找到日期与其前一个日期的最大天数差异)。
我们期望输出:
+-------------+------------+--------+
| date1 | date2 | ddiff |
+-------------+------------+--------+
| 1965-08-10 | 1990-12-29 | 9272 |
+-------------+------------+--------+
因为最大的连续日期差异在1965-08-10
和之间1990-12-29
。
第1步:
为了使上一个和下一个日期彼此并排(为了方便该DATEDIFF
功能),我们要做的第一件事是根据日期的升序为每个日期附加一个排名编号。
因为日期的顺序只能依赖于它们本身(不是自动递增的 ID 或排名字段等),所以我们必须自己手动计算排名。
我们通过使用 MySQL 变量来做到这一点。其他使用变量的解决方案要求您执行三个或更多单独的语句。我在查询本身(通过CROSS JOIN
)中初始化变量的技术将其包含在单个语句中。
SELECT @a_rn:=@a_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @a_rn:=0) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
渲染:
+----------+------------+
| ascrank | date |
+----------+------------+
| 1 | 1950-05-01 |
| 2 | 1965-08-10 |
| 3 | 1990-12-29 |
| 4 | 1990-12-30 |
| 5 | 2012-09-03 |
+----------+------------+
SQLFiddle 演示
请注意WHERE
日期必须在两个指定日期之间的条件。您可以在此处插入脚本中的开始/结束日期参数。
第2步:
现在我们已经对每个日期进行了排名,现在我们需要根据ascrank
字段对结果执行移位内连接,以便我们获得彼此相邻的连续日期。我们通过将结果包装在子选择中来做到这一点。
由于我们需要自连接派生结果,因此我们必须重复上述步骤,只需稍微调整一下参数:
SELECT *
FROM (
SELECT @a_rn:=@a_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @a_rn:=0) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
) a
JOIN (
SELECT @b_rn:=@b_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @b_rn:=-1) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
) b ON a.ascrank = b.ascrank
渲染:
+----------+-------------+----------+------------+
| ascrank | date | ascrank | date |
+----------+-------------+----------+------------+
| 1 | 1950-05-01 | 1 | 1965-08-10 |
| 2 | 1965-08-10 | 2 | 1990-12-29 |
| 3 | 1990-12-29 | 3 | 1990-12-30 |
| 4 | 1990-12-30 | 4 | 2012-09-03 |
+----------+-------------+----------+------------+
SQLFiddle 演示
“稍微调整的参数”只是@b_rn
第二个子选择中的ascrank变量()从而-1
不是开始0
。这样,join 条件就以升序a.ascrank = b.ascrank
加入下一个日期。我们也可以保持两个变量在 处初始化0
,但在 的条件下加入a.ascrank = b.ascrank-1
,这将呈现相同的结果。
但是等等,那个日期发生了什么事5
?由于那是订单中的最后一个日期,因此在它之后没有日期可以取差,所以它不需要出现在结果的左侧,只需要与它的前一个日期进行比较.
第 3 步:
现在我们有了彼此相邻的连续日期,我们可以获取两者DATEDIFF()
之间的日期差(通过):
SELECT a.date date1,
b.date date2,
DATEDIFF(b.date, a.date) ddiff
FROM (
SELECT @a_rn:=@a_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @a_rn:=0) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
) a
JOIN (
SELECT @b_rn:=@b_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @b_rn:=-1) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
) b ON a.ascrank = b.ascrank
渲染:
+-------------+------------+--------+
| date1 | date2 | ddiff |
+-------------+------------+--------+
| 1950-05-01 | 1965-08-10 | 5580 |
| 1965-08-10 | 1990-12-29 | 9272 |
| 1990-12-29 | 1990-12-30 | 1 |
| 1990-12-30 | 2012-09-03 | 7918 |
+-------------+------------+--------+
SQLFiddle 演示
第4步:
现在选择最大值很简单ddiff
。我们通过ORDER BY / LIMIT 1
在现场使用一种技术来做到这一点ddiff
:
SELECT a.date date1,
b.date date2,
DATEDIFF(b.date, a.date) ddiff
FROM (
SELECT @a_rn:=@a_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @a_rn:=0) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
) a
JOIN (
SELECT @b_rn:=@b_rn+1 ascrank,
date
FROM tbl
CROSS JOIN (SELECT @b_rn:=-1) var_init
WHERE date BETWEEN '1950-05-01' AND '2012-09-04'
ORDER BY date
) b ON a.ascrank = b.ascrank
ORDER BY ddiff DESC
LIMIT 1
渲染:
+-------------+------------+--------+
| date1 | date2 | ddiff |
+-------------+------------+--------+
| 1965-08-10 | 1990-12-29 | 9272 |
+-------------+------------+--------+
最终结果的 SQLFiddle 演示
我们已经得出了最终结果。