|
我有一个SELECT有这些表达式Postgres语句:
0 R; F0 @1 Y: e8 |0 A,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在我的具体查询中,有五个字段,其输出取决于是否rtp.team_id =rtp.sub_team_id评估为true。我CASE一遍又一遍地重复具有相同条件的句子。
' Q7 r7 Q3 t9 r2 ? D5 i有什么方法可以组合这些?CASE多列输出一次切换表达式?
9 C6 b( o( @; {) ?& v5 Z1 h 8 ~2 m5 u: G4 C! ]1 V
解决方案:
9 v. \% o! |: H F1 S% W1 Z5 O& n 1. Standard-SQL:LEFT JOIN一行值您可以LEFT JOIN使用条件一行值,使用条件估)获得一行值。然后,您可以使用添加每列的后备值COALESCE()。2 K9 x* u; `* P$ L% i% m7 ?
这种语法变体短,多个值时速度快-特别有趣的是昂贵/冗长的条件:
7 n; B- ]3 G4 a- E1 qSELECT 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_exampleFROM rtpJOIN rtd2 r2 ON <u> -- missing context in questionLEFT 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由 单行 组成,无需其他条件即可连接。
2 J$ o3 M$ O7 p2 J+ X3 q( g__ 必须在子查询中进行转换显式类型
. Q4 m z" d: z! N K3 f6 `。我text在示例中使用(无论如何都是字符串文本的默认设置)。使用您的实际数据类型。语法快捷value::type是Postgres特定的,cast(valueAS type)用于标准SQL。) [ P9 F! F! S
若条件不是TRUE,则inx所有值都是NULL,并COALESCE加入。
; u2 j4 @7 }' S0 L4 x或者 ,因为所有的候选值都来自表rtd你的具体情况,LEFT JOIN来rtd2使用原来的CASE状态,并CROSSJOIN默认值:) i. w4 Z l6 y h( f0 V4 |) q$ C, W
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_exampleFROM rtpLEFT JOIN rtd2 r2 ON <u> -- missing context in question AND rtp.team_id = rtp.sub_team_idCROSS JOIN ( SELECT 'testing'::text AS txt1 'test example'::text AS txt2 'test example #2'::text AS txt3 ) x;它取决于连接条件和查询的其他部分。) F5 y' c9 W! \
2.特定于PostgreSQL2a。展开数组如果您的列共享 _ 数据类型相同_ ,可在子查询中使用数组,然后在外部展开SELECT:! v7 ^# v, n- h0 t% }6 M
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 <u> ) x;如果列不共享相同的数据类型,它将变得更加复杂。你可以把它们都做text转换为(并且可以选择在外部转换SELECT),也可以…& f6 o$ D2 S, B
2b。分解行类型您可以使用自定义的复合类型(行类型)来保存各种类型的值,并且可以简单地在外部*扩展它SELECT。假设我们有三列:text,integer和date。要
9 {2 \8 r- P) K重复 使用时,请创建自定义复合类型:% j+ M2 b! P1 D' O
CREATE TYPE my_type (t1 text,t2 int,t3 date);或者, 如果现有表的类型匹配,只能使用表名作为复合类型。
. o5 @3 w: y ?或者, 如果你只是 临时 如果你需要这种类型,你可以创建一个TEMPORARY TABLE,在 会话 注册临时类型:. o, W# A: o/ R5 |1 J
CREATE TEMP TABLE my_type (t1 text,t2 int,t3 date);甚至可以为 单个事务 执行此操作:) D' `: O" y+ G3 _5 V6 x
CREATE TEMP TABLE my_type (t1 text,t2 int,t3 date) ON COMMIT DROP;然后,您可以使用以下查询:6 r2 D. H- I7 [" @6 V
SELECT (x.combo).* -- parenthesis requiredFROM ( 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 <u> ) x;甚至只是(和上面一样,更简单,更简短,也许不容易理解):& K5 j! _3 t3 k' }4 l. h6 J" z
SELECT (CASE WHEN rtp.team_id = rtp.sub_team_id THEN ('test',3,now()::date)::my_type ELSE (r2.team_name,r2.int_col,r2.date_col)::my_type END).*FROM rtpJOIN rtd2 r2 ON <u>;该CASE表达式一次,每列评估。如果求值不平凡,其他带子查询的变体会更快。 |
|