6

我有一个 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
4

5 回答 5

7

假设(充满信心)您希望在一年中的某些日子之间有日期,而不管年份如何(例如,如果您要发送一批生日贺卡或其他东西),您可以使用以下方法设置测试:

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 行)
于 2012-08-15T12:59:02.127 回答
1

使用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

如果这没有帮助,请扩展您的问题:

  • 您正在使用的表的结构,来自 psql 的\d tablename命令或原始CREATE TABLE语句;
  • 部分样本内容
  • 您遇到问题的查询
  • 预期成绩
于 2012-08-14T03:58:21.823 回答
1

我很确定,@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 毫秒

于 2012-08-18T23:32:42.903 回答
1

您可以使用简单的条件 >= 和 <= 或类似的或使用 between/and 但诀窍是知道您的确切数据类型。有时日期字段包含时间,这就是查询可能出错的地方,因此建议使用一些与日期相关的函数来消除时间问题。在 SQL Server 中执行此操作的常用函数是 datediff 函数。

于 2013-11-21T12:20:40.087 回答
1

您可以使用以下语法。

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 中。

如果将*标记替换为列名,则只能过滤掉该列的值。

希望有帮助..

于 2012-08-14T04:52:41.650 回答