4

我在 Postgresql 的不同字段中拥有一个包含年、月和日的表,但我需要使用“介于”这些字段之间进行查询。我尝试了一些疯狂的事情,但没有任何效果......有人知道帮助我吗?

防爆表:

CREATE TABLE my_table
(
  id serial NOT NULL,
  day integer NOT NULL,
  month integer NOT NULL,
  year integer NOT NULL,
)
4

4 回答 4

8

欺骗。您没有验证这些“日期”,您只是对它们进行排序。验证是一项单独的任务,唯一明智的解决方案是架构更改。

CREATE INDEX my_table__date__idx ON test1 (year * 10000 + month * 100 + day);

SELECT *
FROM my_table
WHERE year * 10000 + month * 100 + day BETWEEN 20130101 AND 20131231;

如果您不想要巨大的差距,请使用year*12*31 + month*31 + day

于 2013-07-16T21:40:31.303 回答
7

帮助黑暗面

在坚持您的设计的同时,这应该比迄今为止提出的任何解决方案都更简单、更快:临时行类型

SELECT *
FROM   tbl
WHERE  (year, month, day) BETWEEN (2013,7,3)
                          AND     (2013,7,5);

db<>fiddle here
sqlfiddle

适当的解决方案

但是,实际上,您应该从一开始就使用适当的表格设计。将日期另存为date,而不是三integer列。这会强制执行有效日期,作为附带利益。

CREATE TABLE tbl (
  tbl_id  serial PRIMARY KEY
, thedate date NOT NULL
);

thedate包括所有三列:day, month,year并且需要 4 个字节,如integer.

那么任务就很简单了:
要获得日、月、年或任何形式的任何子单位,请使用to_char()extract()date_trunc()。这些功能非常快速且用途广泛。

您可以创建一个VIEW看起来与您现在拥有的表格完全相同的表格:

CREATE view old_table AS
SELECT tbl_id
     , EXTRACT(day   FROM thedate)::int AS day
     , EXTRACT(month FROM thedate)::int AS month
     , EXTRACT(year  FROM thedate)::int AS year
FROM   my_table;

仍然至少和你的桌子一样快,因为源更小。

于 2013-07-16T21:55:21.160 回答
2

如果您无法更改表结构以使用正确的日期,则可以从字段中生成日期以进行比较,例如:

SELECT *
FROM Table
WHERE to_date(Year||' '||Day||' '||Month, 'YYYY DD MM') BETWEEN date1 AND date2

如果它们都是整数,您必须将每个整数转换为字符串,我相信::VARCHAR()有效,或者CAST()

SELECT *
FROM Table
WHERE to_date(Year::varchar(4)||' '||Day::varchar(2)||' '||Month::varchar(2), 'YYYY DD MM') BETWEEN date1 AND date2
于 2013-07-16T21:21:16.233 回答
2
WHERE
  (
       ((day >= :first_day) AND (month  = :first_month) AND (year  = :first_year))
    OR (                        (month >  :first_month) AND (year  = :first_year))
    OR (                                                    (year >  :first_year))
  )
  AND
  (
       ((day <= :final_day) AND (month  = :final_month) AND (year  = :final_year))
    OR (                        (month <  :final_month) AND (year  = :final_year))
    OR (                                                    (year <  :final_year))
  )

真的会破坏任何索引搜索的机会。您可能每次都会扫描整个表。

寻找使用真实日期字段会好一百万倍。

我永远不想发布上面的代码,更不用说让同行评审了。我会感到羞愧的。

于 2013-07-16T21:21:48.437 回答