按年份范围(同月和日)过滤年份

时间:2012-08-14 01:57:15

标签: sql database postgresql date postgresql-8.4

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

5 个答案:

答案 0 :(得分: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 rows)

答案 1 :(得分: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语句;
  • 一些示例内容
  • 您遇到问题的查询
  • 预期成果

答案 2 :(得分: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。

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

希望有所帮助..

答案 3 :(得分: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
“非语言环境”C的字符串比较速度更快 - the manual about collation support更多。

SELECT * FROM tbl
WHERE  EXTRACT(MONTH FROM data)*100 + EXTRACT(DAY FROM data)
       BETWEEN 215 AND 621;

总运行时间:209.965 ms

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 ms

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 ms
开头语。


功能索引更快

击败它的唯一方法是使用索引。以上查询都不能在data上使用普通索引。但是,如果读取性能至关重要(并且写入性能的成本很低),您可以使用functional index

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 ms

这就是我最终可以通过头发击败Kevin的查询:使用单列索引而不是他所需的多列索引。

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 ms

答案 4 :(得分:1)

您可以使用简单条件&gt; =和&lt; =或类似或在/之间使用,但技巧是知道您的确切数据类型。 有时日期字段包含时间,这是查询可能出错的地方,因此建议使用一些与日期相关的函数来消除时间问题。在SQL Server中,常见的功能就是具有约会功能。