,CASE WHEN (rtp.team_id = rtp.sub_team_id) THEN 'testing' ELSE TRIM(rtd2.team_name) END AS testing_testing,CASE WHEN (rtp.team_id = rtp.sub_team_id) THEN 'test example' ELSE TRIM(rtd2.normal_data) END AS test_response,CASE WHEN (rtp.team_id = rtp.sub_team_id) THEN 'test example #2' ELSE TRIM(rtd2.normal_data_2) END AS another_example
在我特别的查询中有5个字段,其输出取决于rtp.team_id = rtp.sub_team_id的值是否为true.我一遍又一遍地重复相同条件的CASE语句.
有没有什么办法可以组合这些CASE表达式来一键切换多列的输出?
您可以使用条件(从而评估一次),以LEFT JOIN
的一行值.然后,您可以使用COALESCE()
为每列添加后备值.
这种语法变体比较简单,速度更快,具有多个值 – 对于昂贵/冗长的条件特别有趣:
SELECT COALESCE(x.txt1,trim(r2.team_name)) AS testing_testing,COALESCE(x.txt2,trim(r2.normal_data)) AS test_response,COALESCE(x.txt3,trim(r2.normal_data_2)) AS another_example FROM rtp JOIN rtd2 r2 ON <unknown condition> -- missing context in question LEFT JOIN ( SELECT 'testing'::text AS txt1,'test example'::text AS txt2,'test example #2'::text AS txt3 ) x ON rtp.team_id = rtp.sub_team_id;
由于派生表x由单行组成,无需进一步条件即可进行连接.
子查询中需要显式类型转换.我在示例中使用文本(这也是字符串文字的默认值).使用您的实际数据类型.语法快捷方式value :: type是Postgres特定的,对于标准sql使用cast(值AS类型).
如果条件不为TRUE,x中的所有值都为NULL,并且COALESCE进入.
或者,由于所有候选值来自特定情况下的表rtd2,LEFT使用原始CASE条件加入rtd2,并将CROSS JOIN加入到具有默认值的行中:
SELECT COALESCE(trim(r2.team_name),x.txt1) AS testing_testing,COALESCE(trim(r2.normal_data),x.txt2) AS test_response,COALESCE(trim(r2.normal_data_2),x.txt3) AS another_example FROM rtp LEFT JOIN rtd2 r2 ON <unknown condition> -- missing context in question AND rtp.team_id = rtp.sub_team_id CROSS JOIN ( SELECT 'testing'::text AS txt1,'test example #2'::text AS txt3 ) x;
这取决于连接条件和查询的其余部分.
2. Postgresql特定的
2A.展开数组
如果您的各种列共享相同的数据类型,则可以在子查询中使用数组,并在外部SELECT中展开它:
SELECT x.combo[1],x.combo[2],x.combo[3] FROM ( SELECT CASE WHEN rtp.team_id = rtp.sub_team_id THEN '{test1,test2,test3}'::text[] ELSE ARRAY[trim(r2.team_name),trim(r2.normal_data),trim(r2.normal_data_2)] END AS combo FROM rtp JOIN rtd2 r2 ON <unknown condition> ) x;
如果列不共享相同的数据类型,它会变得更复杂.您可以将它们全部转换为文本(并可选择在外部SELECT中转换),也可以…
2B.分解行类型
您可以使用自定义复合类型(行类型)来保存各种类型的值,并且只需将其扩展到外部SELECT.假设我们有三列:文本,整数和日期.要重复使用,请创建一个自定义复合类型:
CREATE TYPE my_type (t1 text,t2 int,t3 date);
或者如果现有表的类型匹配,则可以使用表名称作为复合类型.
或者如果您只需要临时类型,您可以创建一个TEMPORARY TABLE,它在会话期间注册一个临时类型:
CREATE TEMP TABLE my_type (t1 text,t3 date);
你甚至可以为一个单一的交易:
CREATE TEMP TABLE my_type (t1 text,t3 date) ON COMMIT DROP;
那么你可以使用这个查询:
SELECT (x.combo).* -- parenthesis required FROM ( SELECT CASE WHEN rtp.team_id = rtp.sub_team_id THEN ('test',3,now()::date)::my_type -- example values ELSE (r2.team_name,r2.int_col,r2.date_col)::my_type END AS combo FROM rtp JOIN rtd2 r2 ON <unknown condition> ) x;
或者甚至(同上,更简单,更短,也许不太容易理解):
SELECT (CASE WHEN rtp.team_id = rtp.sub_team_id THEN ('test',now()::date)::my_type ELSE (r2.team_name,r2.date_col)::my_type END).* FROM rtp JOIN rtd2 r2 ON <unknown condition>;
CASE表达式通过这种方式对每一列进行一次评估.如果评估不是微不足道,另一个具有子查询的变体会更快.