【问题标题】:PostgreSQL: How to use char column containing a timestampPostgreSQL:如何使用包含时间戳的 char 列
【发布时间】:2014-10-04 16:15:47
【问题描述】:

我正在使用一个 PostgreSQL 数据库,其中包含一个 char 列,其中包含格式为“前缀:5 月 7 日星期三,上​​午 11:30-1:30”的文本时间戳。没有年份,所有日期都假定在当前年份内。我意识到如果这些数据位于具有时间戳或日期和时间类型的列中,则使用这些数据会更容易,但我无法控制数据库格式,我必须处理那里的内容。

我需要做的是编写一个仅返回具有特定前缀值(例如“public”与“private”)且时间/日期等于当前时间/日期之后的记录的 SELECT。这是一个相对较大的数据库,大约有 100,000 条记录,我需要能够快速进行搜索。任何人都可以就实现这一目标的最佳方式提供建议吗?我考虑过使用正则表达式或 to_date() 和 substring() 的组合,但我不确定如何继续。

额外问题:有没有办法使用此字段按日期和时间顺序排列记录?

【问题讨论】:

  • 不幸的是,这是一个可怕的设计......使用这种格式,您将永远无法在表上放置一个像样的日期索引,并且所有查询都会受到它的影响。我的第一个想法 - 有没有能力创建自己的数据仓库并创建一个 etl 进程来导入这个表?我们可以通过查询来读取该日期字段并理解它,但我不确定您是否会在无法更改该表的情况下看到良好的速度
  • 您的日期时间格式中没有年份。你怎么知道真正的日期是什么?
  • @GordonLinoff: "所有日期都假定在当年"
  • @Twelfth,我同意这个设计。我见过的最疯狂的事情,但我没有机会改变它。我无法创建其他表或数据库。在这一点上,我所能做的就是尝试找到我能想到的最快的 SELECT,它可以按原样处理数据。
  • @steevithak - 有时你必须做你必须做的事情......我会确保你建议任何人围绕这个数据库做出决定,它设计得非常糟糕,没有授权改变结构,速度可能会保持相当缓慢。随着时间的流逝,数据丢失(并且很可能出现功能问题......如果您获得两个相同的日期/时间条目,一个来自 2013 年和 2014 年,会发生什么?)您在此处提出的任何解决方案都可能在 6 个月内失效。否则 Gordons 解决方案看起来不错

标签: sql regex postgresql select timestamp


【解决方案1】:

我认为这样的事情会起作用:

select split_part(col, ':', 1) as prefix,
       to_timestamp(to_char(now(), 'YYYY') || 
                    split_part(col, ':', 2),
                    'YYYY Dy Mon dd, HH:MIAM'
                   ) as DateTime

【讨论】:

    【解决方案2】:

    如果您需要能够将日期用作范围,则可以使用 Postgres 范围功能。 (或者您当然可以只设置开始日期和结束日期。两者都在下面的示例中完成。)

    WITH initial_strings AS (
    SELECT 'Public: Wed May 7, 11:30AM-1:30PM'::varchar as char_time),
    
    split_up AS
    (
    SELECT
    split_part(char_time, ':', 1) prefix,
    split_part(split_part(char_time,',',2), '-', 1)::TIME start_time,
    split_part(split_part(char_time,',',2), '-', 2)::TIME end_time,
    to_timestamp(to_char(now(), 'YYYY') || 
                split_part(split_part(char_time,',',1), ':', 2),
                'YYYY Dy Mon dd'
                ) as the_day
    FROM initial_strings),
    
    new_format AS
    (
    SELECT 
    prefix,
    tstzrange((the_day + start_time),(the_day + end_time)) time_range,
    the_day + start_time started_at,
    the_day + end_time ended_at
    FROM split_up
    ORDER BY started_at) --Performs the required ordering
    
    SELECT *
    FROM new_format
    WHERE prefix = 'Public'
    AND started_at >= '2014-05-07';
    

    这当然假设您的时间总是在同一天。如果不是这种情况,您的拆分就必须稍微复杂一点,但这应该只是对此稍作修改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-12
      • 2021-09-14
      • 1970-01-01
      • 2014-11-21
      相关资源
      最近更新 更多