如何 SELECT TO_CHAR 与列表 {11:00:00,12:00:00}

How to SELECT TO_CHAR with list {11:00:00,12:00:00}

我有这个table:

postgres::DATABASE=> SELECT * FROM db;
       timeList     |   time   
---------+------------+---------------------
{11:00:00,12:00:00} | 11:22:33
{19:00:00}          | 12:12:33

我需要 select timeList 没有秒的值。但是收到此错误:

postgres::DATABASE=> SELECT TO_CHAR(timeList, 'HH24:MI') timeList FROM db;

ERROR:  syntax error at or near "timeList"
LINE 1: SELECT TO_CHAR(time, 'HH24:MI') timeList FROM db;
                                        ^

select 单个值的命令按预期工作:

postgres::DATABASE=> SELECT TO_CHAR(time, 'HH24:MI') time FROM db;
 time  
-------
 11:22
 12:12

由于您的非规范化数据模型,您必须使用 unnestarray_agg:

SELECT array_agg(to_char(tl.tle, 'HH24:MI') ORDER BY tl.n),
       to_char(db.time, 'HH24:MI')
FROM db
   CROSS JOIN LATERAL unnest(db.timelist) WITH ORDINALITY AS tl(tle, n)
GROUP BY db;

又快又脏

假设列 "timeList" 的类型为 time[],有一种快速而肮脏的方法。转换为 varchar(5)[] 会截断时间的字符串表示形式,以便仅保留 HH24:MI。

test=> SELECT '{12:12, 1:1:1.123456, 23:59:59.999999}'::time[]::varchar(5)[];
       varchar       
---------------------
 {12:12,01:01,23:59}
(1 row)

db<>fiddle here

它甚至开箱即用地正确表示 NULL 和空数组。对于“quick'n'dirty”来说非常干净。

当然,这取决于 time 值的文本表示的实现细节。但它适用于我所知道的任何可能的设置,而且我认为它不会很快改变。相关:

缓慢而确定

要以您想要的任何方式格式化输出,Laurenz 总是提供缓慢而可靠的方法:取消嵌套、格式化、聚合。但是在 LATERAL 子查询中使用 ARRAY 构造函数立即返回聚合通常更快。这也保证保持数组元素的原始顺序而不用跟踪 WITH ORDINALITY:

SELECT *
FROM   db, LATERAL (
   SELECT ARRAY(SELECT to_char(unnest(db.timelist), 'HH24:MI'))
   ) x(times_formatted);

此外,子查询的聚合总是产生一行,因此它不会在主 table 中默默地消除具有 NULL 或空数组 ({}) 的行(就像 Laurenz 的查询那样) .

隐式 CROSS JOIN 仍然有副作用:它将 NULL 转换为空数组 ({})。
可以用这样的 LEFT JOIN 来正确避免:

SELECT *
FROM   db
LEFT   JOIN LATERAL (
   SELECT ARRAY(SELECT to_char(unnest(db.timelist), 'HH24:MI'))
   ) x(times_formatted) ON db.timelist IS NOT NULL;

考虑 fiddle 中的演示。

db<>fiddle here

相关: