ruby-on-rails - 是否可以以与数据库无关的方式将日期搜索为字符串?

标签 ruby-on-rails postgresql search database-agnostic

我有一个带有 PostgreSQL 数据库的 Ruby on Rails 应用程序;几个表具有 created_at 和 updated_at 时间戳属性。显示时,这些日期会以用户的语言环境进行格式化;例如,时间戳 2009-10-15 16:30:00.435 变为字符串 15.10.2009 - 16:30(此示例的日期格式为 dd.mm.yyyy - hh.mm).

要求是用户必须能够按日期搜索记录,就好像它们是在当前语言环境中格式化的字符串一样。例如,搜索 15.10.2009 将返回日期为 2009 年 10 月 15 日的记录,搜索 15.10 将返回日期为任何一年的 10 月 15 日的记录,搜索 15 将返回匹配 15 的所有日期(无论是日、月还是年)。由于用户可以使用日期的任何部分作为搜索词,因此无法将其转换为日期/时间戳以进行比较。

一种(慢速)方法是检索所有记录,格式化日期,然后对其执行搜索。这可以通过首先只检索 id 和日期,执行搜索,然后获取匹配记录的数据来加快;但对于大量行来说它仍然可能很慢。

另一种(与数据库无关的)方法是使用 PostgreSQL 函数或运算符将日期转换/格式化为数据库中的正确格式,并让数据库进行匹配(使用 PostgreSQL 正则表达式运算符或诸如此类)。

有没有办法以与数据库无关的方式高效地执行此操作(无需获取所有行)?还是您认为我走错了方向,应该以不同的方式处理问题?

最佳答案

根据 Carlos 的回答,如果您在所有日期和日期部分字段上都有索引,这应该允许您进行所有搜索而无需全表扫描。基于函数的索引对于日期部分列会更好,但我没有使用它们,因为这不应该是特定于数据库的。

CREATE TABLE mytable (
    col1 varchar(10),
    -- ...
    inserted_at timestamp,
    updated_at timestamp);

INSERT INTO mytable
VALUES
    ('a', '2010-01-02', NULL),
    ('b', '2009-01-02', '2010-01-03'),
    ('c', '2009-11-12', NULL),
    ('d', '2008-03-31', '2009-04-18');

ALTER TABLE mytable
    ADD inserted_at_month integer,
    ADD inserted_at_day integer,
    ADD updated_at_month integer,
    ADD updated_at_day integer;

-- you will have to find your own way to maintain these values...
UPDATE mytable
SET
    inserted_at_month = date_part('month', inserted_at),
    inserted_at_day = date_part('day', inserted_at),
    updated_at_month = date_part('month', updated_at),
    updated_at_day = date_part('day', updated_at);

如果用户仅输入年份,请使用 WHERE Date BETWEEN 'YYYY-01-01' AND 'YYYY-12-31'

SELECT *
FROM mytable
WHERE
    inserted_at BETWEEN '2010-01-01' AND '2010-12-31'
    OR updated_at BETWEEN '2010-01-01' AND '2010-12-31';

如果用户输入年份和月份,请使用 WHERE Date BETWEEN 'YYYY-MM-01' AND 'YYYY-MM-31'(可能需要调整 30/29/28)

SELECT *
FROM mytable
WHERE
    inserted_at BETWEEN '2010-01-01' AND '2010-01-31'
    OR updated_at BETWEEN '2010-01-01' AND '2010-01-31';

如果用户输入这三个值,请使用 SELECT .... WHERE Date = 'YYYY-MM-DD'

SELECT *
FROM mytable
WHERE
    inserted_at = '2009-11-12'
    OR updated_at = '2009-11-12';

如果用户输入月和日

SELECT *
FROM mytable
WHERE
    inserted_at_month = 3
    OR inserted_at_day = 31
    OR updated_at_month = 3
    OR updated_at_day = 31;

如果用户输入月或日(您可以优化为不检查值 > 12 作为一个月)

SELECT *
FROM mytable
WHERE
    inserted_at_month = 12
    OR inserted_at_day = 12
    OR updated_at_month = 12
    OR updated_at_day = 12;

关于ruby-on-rails - 是否可以以与数据库无关的方式将日期搜索为字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2175844/

相关文章:

ruby-on-rails - 是否可以使用 FTP 编写和编辑 etc/default/unicorn ? ForR,Ubuntu 12.10 服务器 Digitalocean

ruby-on-rails - 将 Amazon Simple Notification service SNS 与 ruby​​ 结合使用

Facebook "OR"使用图形 API 查询

PostgreSQL 9.6 wals管理

SQL:使用两个查询的结果计算 %

php - 搜索在 Laravel 5.1 中不起作用

javascript - 检查对象数组是否包含给定字符串

ruby-on-rails - ActionView::Template::Error(未预编译):在 heroku cedar 上

ruby-on-rails - Ruby on Rails : What id do I want here?

linux - 无法在远程 Linux VM 上 pg_restore SQL 文件