SQL - DATEDIFF 和 WHERE/HAVING 的聚合函数
SQL - Aggregate Function for DATEDIFF and WHERE/HAVING
我正在尝试查询数据库以查找与我传入的参数最接近的日期。
我有一个问题,我一直在 IRC 和列表中处理一段时间,但找不到解决方案。我正在使用 python DBAPI (sqlalchemy) 并通过 CLI 和 Flask 应用程序访问数据(但这不应该影响 SQL)。数据库 MySQL 带有 InnoDB 引擎。
查询将取决于名为 target_expiration
的因素,但数据库中通常不存在该因素的值。我需要找到最接近的值。例如,我将传递 target_date='2015-06-02'
并希望它对我来说 return 2015-06-03
结果和 2015-06-01
距离我 [=18] 一天的结果=].
尝试解决方案:
SELECT * FROM table1 HAVING MIN(ABS(DATEDIFF(table1.Expiration,
'2015-06-02'))) = ABS(DATEDIFF(table1.Expiration, '2015-06-02'));
这 return 没有行。我可以 运行 相同的 MIN(ABS(DATEDIFF(...)))
到 return a scalar()
它成功并打印一个值。
我尝试使用 HAVING
函数来使用聚合函数。我正在寻找扫描数据库并找出离我的目标日期最近的到期日期。如果它为零,我就完成了 - 我找到了日期,然后我只想 return 所有匹配的日期。如果是一天之后,我不知道是向前一天还是向后一天(我将处理添加更多功能以供稍后选择,但现在我只想 return 所有值向前或向后 n
天)。
示例数据: table1
这是一个极其有限的数据样本,实际上我有大约 40 列和数十亿行,所以速度是一个因素。
+------------+-------------+-------+
| Expiration | ProductType | Price |
+------------+-------------+-------+
| 2015-06-01 | 2 | 25 |
+------------+-------------+-------+
| 2015-06-03 | 1 | 22 |
+------------+-------------+-------+
| 2015-05-28 | 1 | 22 |
+------------+-------------+-------+
| 2015-05-28 | 2 | 28 |
+------------+-------------+-------+
| 2015-05-28 | 1 | 22 |
+------------+-------------+-------+
| 2015-06-04 | 2 | 28 |
+------------+-------------+-------+
| 2015-05-25 | 1 | 22 |
+------------+-------------+-------+
| 2015-05-25 | 2 | 28 |
+------------+-------------+-------+
单个结果:
SELECT *
FROM table1
ORDER BY ABS(DATEDIFF(table1.Expiration, '2015-06-02')) ASC
LIMIT 1;
如果您担心 "tie":
SELECT *
FROM table1
WHERE ABS(DATEDIFF(table1.Expiration, '2015-06-02')) = (
SELECT MIN(ABS(DATEDIFF(table1.Expiration, '2015-06-02')))
FROM table1
);
但是请注意,这些查询永远不会很快;第二个要求 table 中的每一行都被检查两次,并且在这两个函数中使用都阻止索引提供任何帮助。
简单如何
SELECT *
FROM table1
ORDER BY ABS(DATEDIFF(Expiration, '2015-06-02'));
或者,如果 table 很大,并且您有 INDEX(Expiration)
,这应该更快:
( SELECT *,
ABS(DATEDIFF(Expiration, '2015-06-02')) AS diff
FROM table1
WHERE Expiration >= '2015-06-02'
ORDER BY Expiration ASC LIMIT 1 )
UNION ALL
( SELECT *,
ABS(DATEDIFF(Expiration, '2015-06-02')) AS diff
FROM table1
WHERE Expiration < '2015-06-02'
ORDER BY Expiration DESC LIMIT 1 )
ORDER BY diff
LIMIT 1;
我正在尝试查询数据库以查找与我传入的参数最接近的日期。
我有一个问题,我一直在 IRC 和列表中处理一段时间,但找不到解决方案。我正在使用 python DBAPI (sqlalchemy) 并通过 CLI 和 Flask 应用程序访问数据(但这不应该影响 SQL)。数据库 MySQL 带有 InnoDB 引擎。
查询将取决于名为 target_expiration
的因素,但数据库中通常不存在该因素的值。我需要找到最接近的值。例如,我将传递 target_date='2015-06-02'
并希望它对我来说 return 2015-06-03
结果和 2015-06-01
距离我 [=18] 一天的结果=].
尝试解决方案:
SELECT * FROM table1 HAVING MIN(ABS(DATEDIFF(table1.Expiration,
'2015-06-02'))) = ABS(DATEDIFF(table1.Expiration, '2015-06-02'));
这 return 没有行。我可以 运行 相同的 MIN(ABS(DATEDIFF(...)))
到 return a scalar()
它成功并打印一个值。
我尝试使用 HAVING
函数来使用聚合函数。我正在寻找扫描数据库并找出离我的目标日期最近的到期日期。如果它为零,我就完成了 - 我找到了日期,然后我只想 return 所有匹配的日期。如果是一天之后,我不知道是向前一天还是向后一天(我将处理添加更多功能以供稍后选择,但现在我只想 return 所有值向前或向后 n
天)。
示例数据: table1
这是一个极其有限的数据样本,实际上我有大约 40 列和数十亿行,所以速度是一个因素。
+------------+-------------+-------+
| Expiration | ProductType | Price |
+------------+-------------+-------+
| 2015-06-01 | 2 | 25 |
+------------+-------------+-------+
| 2015-06-03 | 1 | 22 |
+------------+-------------+-------+
| 2015-05-28 | 1 | 22 |
+------------+-------------+-------+
| 2015-05-28 | 2 | 28 |
+------------+-------------+-------+
| 2015-05-28 | 1 | 22 |
+------------+-------------+-------+
| 2015-06-04 | 2 | 28 |
+------------+-------------+-------+
| 2015-05-25 | 1 | 22 |
+------------+-------------+-------+
| 2015-05-25 | 2 | 28 |
+------------+-------------+-------+
单个结果:
SELECT *
FROM table1
ORDER BY ABS(DATEDIFF(table1.Expiration, '2015-06-02')) ASC
LIMIT 1;
如果您担心 "tie":
SELECT *
FROM table1
WHERE ABS(DATEDIFF(table1.Expiration, '2015-06-02')) = (
SELECT MIN(ABS(DATEDIFF(table1.Expiration, '2015-06-02')))
FROM table1
);
但是请注意,这些查询永远不会很快;第二个要求 table 中的每一行都被检查两次,并且在这两个函数中使用都阻止索引提供任何帮助。
简单如何
SELECT *
FROM table1
ORDER BY ABS(DATEDIFF(Expiration, '2015-06-02'));
或者,如果 table 很大,并且您有 INDEX(Expiration)
,这应该更快:
( SELECT *,
ABS(DATEDIFF(Expiration, '2015-06-02')) AS diff
FROM table1
WHERE Expiration >= '2015-06-02'
ORDER BY Expiration ASC LIMIT 1 )
UNION ALL
( SELECT *,
ABS(DATEDIFF(Expiration, '2015-06-02')) AS diff
FROM table1
WHERE Expiration < '2015-06-02'
ORDER BY Expiration DESC LIMIT 1 )
ORDER BY diff
LIMIT 1;