【问题标题】:Dynamic (Column Based) Interval动态(基于列)间隔
【发布时间】:2011-07-13 02:41:14
【问题描述】:

如何向 NOW 添加动态(基于列的)天数?

SELECT NOW() + INTERVAL a.number_of_days "DAYS" AS "The Future Date" 
FROM a;

a.number_of_days 是一个整数?

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    根据列 ID 进行更新是为我创建一些随机测试数据的有用方法。

    update study_histories set last_seen_at = now() - interval '3 minutes' * id;
    

    【讨论】:

      【解决方案2】:

      使用make_interval()

      SELECT NOW() + make_interval(days => a.number_of_days) AS "The Future Date" 
      FROM a;
      

      但一般来说,使用定义为interval 的列可能会更好,然后您可以在其中存储值时使用所需的任何单位。

      【讨论】:

      • days => a.number_of_days 似乎是 Postgres 的关键字语法,而 make_interval 只有 yearsmonthsweeksdayshoursmins 和 @ 的参数987654331@。这意味着它不适用于像 interval '1 millisecond' * msTime 这样的所有单位,但对于大多数情况来说,它仍然是一个公平的选择。
      • @VLRoyrenn: secs 接受double value 所以如果你想要毫秒使用secs => 0.001
      【解决方案3】:

      我更喜欢这种方式。我认为它非常简单和干净。 在 postgre 中,您需要 interval+ 运算符与 timestamp 一起使用

      select (3||' seconds')::interval;
      
      select now()+ (10||' seconds')::interval,now();
      

      您可以在哪里使用秒、分钟...天、月... 并且您可以将数字替换为您的列。

      select now()+ (column_name||' seconds')::interval,now()
      from your_table;
      

      【讨论】:

        【解决方案4】:

        要创建基于列值的间隔,我建议在表中添加两列。例如,列“period_value”::INT4 和列“period_name”::VARCHAR。 “period_name”列可以存储以下值:

        • 微秒
        • 毫秒
        • 分钟
        • 小时
        • 季度
        • 十年
        • 世纪
        • 千年
        +--------------+--------------+ |周期值 |期间名称 | +--------------+--------------+ | 2 |分钟 | +--------------+--------------+

        现在你可以写了:

        SELECT NOW() - (period_value::TEXT || ' ' || period_name::TEXT)::INTERVAL FROM table;
        

        【讨论】:

        • 您实际上是在实现数据类型interval 已经提供的功能。创建interval 类型的单列将是比这个 hack 更好的解决方案。
        【解决方案5】:

        如果我们有带有间隔字符串值的字段,例如“41 年 11 月 4 天”,并且想要将其转换为出生日期,请使用此查询:

        UPDATE "february14" set dob = date '2014/02/01'  - (patient_age::INTERVAL) 
        

        dob 是将 '41 years 11 mons 4 days' 转换为 '1972/10/14' 的日期字段,例如
        patient_age 是 varchar 字段,其字符串类似于 '41 years 11 mons 4 days'

        这是将年龄转换回出生日期的查询

        SELECT now() - INTERVAL '41 years 10 mons 10 days';
        

        【讨论】:

          【解决方案6】:

          我知道这是一岁了,但是如果您需要使用列来指定实际间隔(例如“天”、“月”,那么值得知道您也可以将字符串转换为间隔,给予:

          SELECT now()+ CAST(the_duration||' '||the_interval AS Interval)
          

          所以原来的问题会变成:

          SELECT now() + CAST(a.number_of_days||" DAYS" AS Interval) as "The Future Date" FROM a;
          

          【讨论】:

          • 如果您想更好地控制单位列中的值,您可以自己解码:select *, num * case unit when 'W' then '1 week'::interval when 'D' then '1 day'::interval when 'H' then '1 hour'::interval end from (values(1,'W'),(2,'D'),(3,'H')) x(num, unit)
          • 谢谢,这对我帮助很大。但是不要忘记更改postgres的引号:SELECT now() + CAST(a.number_of_days||' DAYS' AS Interval) as "The Future Date" FROM a;
          【解决方案7】:

          我通常将数字乘以 interval '1 day' 或类似值,例如:

          select now() + interval '1 day' * a.number_of_days from a;
          

          【讨论】:

          • 7 年后,这仍然是最好的解决方案。太棒了。
          • 不错的技巧,但在我看来,更好的解决方案是下面的解决方案,他们使用 CAST 或 ::interval 将连接的字段转换为间隔。
          • Paul S 有一个更灵活的解决方案。
          • 为什么你认为@DeniseMeander 是一个更好的解决方案?
          • 老实说,这太棒了
          猜你喜欢
          • 1970-01-01
          • 2020-10-12
          • 2017-11-10
          • 2021-04-06
          • 2021-01-24
          • 1970-01-01
          • 2016-06-04
          • 1970-01-01
          • 2012-12-23
          相关资源
          最近更新 更多