我有一个 PostgreSQL 数据库,其中有一个保存日期的表。现在我需要在所有年份中找到日期范围内的所有行,15/02
直到21/06
(日/月)。
示例结果:
1840-02-28
1990-06-21
1991-02-15
1991-04-25
1992-05-30
1995-03-04
1995-04-10
2001-02-03
2010-04-06
我有一个 PostgreSQL 数据库,其中有一个保存日期的表。现在我需要在所有年份中找到日期范围内的所有行,15/02
直到21/06
(日/月)。
示例结果:
1840-02-28
1990-06-21
1991-02-15
1991-04-25
1992-05-30
1995-03-04
1995-04-10
2001-02-03
2010-04-06
假设(充满信心)您希望在一年中的某些日子之间有日期,而不管年份如何(例如,如果您要发送一批生日贺卡或其他东西),您可以使用以下方法设置测试:
CREATE TABLE d (dt date);
COPY d FROM STDIN;
1840-02-28
1990-06-21
1991-02-15
1991-04-25
1992-05-30
1995-03-04
1995-04-10
2001-02-03
2010-04-06
\.
您可以使用“行值构造函数”轻松选择所需的范围:
SELECT * FROM d
WHERE (EXTRACT(MONTH FROM dt), EXTRACT(DAY FROM dt))
BETWEEN (2, 15) AND (6, 21);
产生:
dt ------------ 1840-02-28 1990-06-21 1991-02-15 1991-04-25 1992-05-30 1995-03-04 1995-04-10 2010-04-06 (8 行)
使用WHERE
带有运算符的子句BETWEEN
。看:
http://www.postgresql.org/docs/current/static/functions-comparison.html#FUNCTIONS-COMPARISON
和:
http://www.postgresql.org/docs/current/static/sql-select.html http://www.postgresql.org/docs/current/static/tutorial.html
如果这没有帮助,请扩展您的问题:
\d tablename
命令或原始CREATE TABLE
语句;我很确定,@kgrittn 对问题的解释是准确的,我喜欢他优雅地使用行构造函数。在我测试了几个替代方案之后更是如此,但没有一个可以与性能相匹配:
使用 65426 行的真实生活表进行测试;32107 合格。PostgreSQL 9.1.4,最好的五个EXPLAIN ANALYZE
:
SELECT * FROM tbl
WHERE to_char(data, 'MMDD') BETWEEN '0215' AND '0621';
总运行时间:251.188 毫秒
SELECT * FROM tbl
WHERE to_char(data, 'MMDD')::int BETWEEN 215 AND 621;
总运行时间:250.965 毫秒
SELECT * FROM tbl
WHERE to_char(data, 'MMDD') COLLATE "C" BETWEEN '0215' AND '0621';
总运行时间:221.732 ms
使用“non-locale”进行字符串比较更快C
- 更多关于排序规则支持的手册。
SELECT * FROM tbl
WHERE EXTRACT(MONTH FROM data)*100 + EXTRACT(DAY FROM data)
BETWEEN 215 AND 621;
总运行时间:209.965 毫秒
SELECT * FROM tbl
WHERE EXTRACT(MONTH FROM data) BETWEEN 3 AND 5
OR EXTRACT(MONTH FROM data) = 2 AND EXTRACT(DAY FROM data) >= 15
OR EXTRACT(MONTH FROM data) = 6 AND EXTRACT(DAY FROM data) <= 21;
总运行时间:160.169 毫秒
SELECT * FROM tbl
WHERE EXTRACT(MONTH FROM data) BETWEEN 2 AND 6
AND CASE EXTRACT(MONTH FROM data)
WHEN 2 THEN EXTRACT(DAY FROM data) >= 15
WHEN 6 THEN EXTRACT(DAY FROM data) <=21
ELSE TRUE END;
总运行时间:147.390 毫秒
SELECT * FROM tbl
WHERE CASE EXTRACT(MONTH FROM data)
WHEN 3 THEN TRUE
WHEN 4 THEN TRUE
WHEN 5 THEN TRUE
WHEN 2 THEN EXTRACT(DAY FROM data) >= 15
WHEN 6 THEN EXTRACT(DAY FROM data) <= 21
ELSE FALSE END;
总运行时间:131.907 毫秒
@Kevin 使用行构造函数的解决方案:
SELECT * FROM tbl
WHERE (EXTRACT(MONTH FROM data), EXTRACT(DAY FROM data))
BETWEEN (2, 15) AND (6, 21);
总运行时间:125.460 毫秒前导
。
打败它的唯一方法是使用索引。上面的查询都不能在data
. 但是,如果读取性能至关重要(并且写入性能的成本很小),您可以使用功能索引:
CREATE INDEX ON tbl(EXTRACT(MONTH FROM data), EXTRACT(DAY FROM data));
SELECT * FROM tbl
WHERE (EXTRACT(MONTH FROM data), EXTRACT(DAY FROM data))
BETWEEN (2, 15) AND (6, 21);
总运行时间:85.895 毫秒
这就是我最终可以击败凯文的查询的地方:使用单列索引而不是他的案例所需的多列索引。
CREATE INDEX ON tbl(
CAST(EXTRACT(MONTH FROM data) * 100 + EXTRACT(DAY FROM data) AS int));
SELECT * FROM tbl
WHERE (EXTRACT(MONTH FROM data) * 100 + EXTRACT(DAY FROM data))::int
BETWEEN 215 AND 621;
总运行时间:84.215 毫秒
您可以使用简单的条件 >= 和 <= 或类似的或使用 between/and 但诀窍是知道您的确切数据类型。有时日期字段包含时间,这就是查询可能出错的地方,因此建议使用一些与日期相关的函数来消除时间问题。在 SQL Server 中执行此操作的常用函数是 datediff 函数。
您可以使用以下语法。
SELECT * FROM tableName WHERE dateColumnName BETWEEN '2012.01.01' AND '2012.08.14';
只需替换以下内容;
tableName - Name of the table you are going to access
dateColumnName - Name of the column whch contains dates
2012.08.1 - Start date
2012.08.21 - End date
输入两个日期时,请仔细检查上面的示例。以相同的格式输入,并将它们括在''
s 中。
如果将*
标记替换为列名,则只能过滤掉该列的值。
希望有帮助..