【问题标题】:How to format dates as ordinal numbers in a text, in a postgres query?如何在 postgres 查询中将日期格式化为文本中的序数?
【发布时间】:2022-11-04 17:29:50
【问题描述】:

我正在寻找构建一个过滤器组件,其中 我的搜索就像b_cycle_type = '1st Day Of The Month'

并且在数据库中b_cycle_type 存储为 -1,0,1,2,3,4,5

如何准备 postgres 声明

我在尝试:

SELECT "customers".* 
FROM   "customers" 
WHERE (CASE customers.b_cycle_type
         WHEN -1 THEN 'Last day of the month'
         WHEN  0 THEN 'Align with first'
         ELSE to_char(customers.b_cycle_type, '99th') || ' Day Of The Month'
       END = '27th Day Of The Month')

它没有返回任何结果。

【问题讨论】:

    标签: ruby-on-rails postgresql


    【解决方案1】:

    这部分to_char(customers.b_cycle_type, '99th') 实际上导致' 27th'(to_char Docs [* 6th from the bottom]) 所以为了解决这个问题,我将使用 TRIM 函数。

    CREATE TABLE customers(
       id SERIAL PRIMARY KEY, 
       b_cycle_type INT);
    INSERT INTO customers(b_cycle_type)
    SELECT * FROM generate_series(-1,30);
    
    SELECT "customers".*
    FROM "customers"
    WHERE 
      CASE b_cycle_type
       WHEN -1 THEN 'Last day of the month'
       WHEN 0 THEN 'Align with first'
       ELSE
         TRIM(to_char(b_cycle_type, '99th')) || ' Day Of The Month'
     END = '27th Day Of The Month'
    

    Example

    您可以避免使用原始 SQL,但它并不漂亮

    your_variable = '27th Day Of The Month'
    customer_table = Customer.arel_table 
    case_stmt = Arel::Case.new(customer_table[:b_cycle_type])
                  .when(-1).then(Arel.sql("'Last day of the month'"))
                  .when(0).then(Arel.sql("'Align with first'"))
                  .else(
                     Arel::Nodes::InfixOperation.new('||'
                       Arel::Nodes::NamedFunction.new('TRIM',[
                         Arel::Nodes::NamedFunction.new('to_char',
                           [customer_table[:b_cycle_type],Arel.sql("'99th'")])
                       ]),
                       Arel.sql("' Day Of The Month'")
                     )
                  )
    Customer.where(case_stmt.eq(your_variable))
    

    【讨论】:

    • 我最初完全忽略了核心问题是to_char() 的怪癖。现在我不确定是否最好将我的答案留在对正在使用的数据类型的评论中,或者将其作为基本上重复的内容撤回(现在缺少 RoR 上下文)。
    • @Zegarek 它添加了我想说的上下文。也许我的帮助一个人,你的帮助另一个¯_(ツ)_/¯。
    【解决方案2】:
    SELECT "customers".* 
    FROM "customers" 
    WHERE (CASE b_cycle_type
             WHEN -1 THEN 'Last day of the month'
             WHEN 0 THEN 'Align with first'
             ELSE 
               CASE 
                  WHEN "customers".b_cycle_type BETWEEN -1 AND 31 
                  THEN trim(to_char("customers".b_cycle_type,'99th')||' Day Of The Month')
               END
          END = '27th Day Of The Month');
    

    但:

    1. 如果b_cycle_type 列是日期,则应将该列定义为date 类型,而不是数字类型。它将使您能够简单地执行where extract('day' from b_cycle_type) = 27。它还将负责验证任何人试图插入表中的所有数据,而无需维护自定义触发器和约束。
    2. 如果出于某种原因您必须将此作为日期偏移量,您应该将其设为smallint 甚至decimal(2,0)。此外,将其对应的实际日期另存为单独的列,以便能够轻松说明具有不同长度的月份,以及二月较长的闰年。
    3. 如果您无法更改"customers" 表结构,则在处理表中的数据时,应确保b_cycle_type 介于-1 和31 之间,并且在给定月份的可能天数内在给定的年份。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 2015-03-05
      • 2023-01-21
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多