如何 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
由于您的非规范化数据模型,您必须使用 unnest
和 array_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
相关:
我有这个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
由于您的非规范化数据模型,您必须使用 unnest
和 array_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
相关: