有没有办法根据一个条件生成多个列?我的感觉就像:
SELECT
CASE WHEN condition_column = 'condition true' and (condition_column2 = 'condition true' or condition_column3 = 'condition true')
THEN column1 as new_column1
AND column2 as new_column2
AND column3 as new_column3
ELSE column2 as new_column1
AND column3 as new_column2
AND column1 as new_column3
我目前的做法是:
SELECT
CASE WHEN condition_column = 'condition true' and (condition_column2 = 'condition true' or condition_column3 = 'condition true')
THEN column1 ELSE column2 END AS new_column1,
CASE WHEN condition_column = 'condition true' and (condition_column2 = 'condition true' or condition_column3 = 'condition true')
THEN column2 ELSE column3 END AS new_column2,
CASE WHEN condition_column = 'condition true' and (condition_column2 = 'condition true' or condition_column3 = 'condition true')
THEN column3 ELSE column1 END AS new_column3
但是在条件复杂的情况下,这会成为很长的一系列陈述。
答案 0 :(得分:2)
你必须尝试一种完全不同的方法。 其中一个 :
LEFT JOIN
/ UNION ALL
UNION ALL
与CTE。
WITH cte AS (
SELECT tbl_id, col1, col2, col3
FROM tbl
WHERE condition_col = 'cond true'
AND 'cond true' IN (condition_col2, condition_col3)
)
SELECT t.tbl_id, t.col2 AS new1, t.col3 AS new2, t.col1 AS new3
FROM tbl t
LEFT JOIN cte c USING (tbl_id)
WHERE c.tbl_id IS NULL
UNION ALL
TABLE cte
ORDER BY tbl_id
tbl_id
是此方案中的主键。
数组只能包含相同基类型的值。如果所有相关列共享相同类型,则根据单个条件选择整个数组。要再次取消该数组,请使用如下子查询:
SELECT tbl_id, a[1] AS new1, a[2] AS new2
FROM (
SELECT tbl_id, CASE WHEN TRUE THEN ARRAY[col1, col2]
ELSE ARRAY[col2, col3] END AS a
FROM tbl
) x;
如果您有不同类型的列,则可以强制转换所有类型,通常text
(并且可选择强制转换)在下一级:
SELECT tbl_id, a[1] AS new1, a[2] AS new2
FROM (
SELECT tbl_id, CASE WHEN TRUE THEN ARRAY[col1::text, col2::text]
ELSE ARRAY[col2::text, col3::text] END AS a
FROM tbl
) x;
要避免使用子查询级别和转换类型,可以使用记录类型。这里的障碍是Postgres只能删除已注册(众所周知)的记录类型。
SELECT tbl_id, (CASE WHEN TRUE THEN (col1::text, col2::int)
ELSE (col2::text, col3::int) END).*
FROM tbl;
对于匿名记录,你会得到:
ERROR: record type has not been registered
但您可以使用已注册记录类型 - 例如隐式创建的表或视图类型或使用CREATE TYPE
显式创建的类型。为了这个演示,我明确地创建了一个类型:
CREATE TYPE foo AS (new1 text, new2 int);
然后,您可以根据单个CASE
表达式选择多个列,并在同一步骤中删除该记录:
SELECT tbl_id, (CASE WHEN TRUE THEN (col1::text, col2::int)::foo
ELSE (col2::text, col3::int)::foo END).*
FROM tbl;
适用于任何类型(甚至相同类型)的列。括号括号是强制性的。
对于即席查询,您不必保留新类型。相反,创建一个临时表,它会随会话而死:
CREATE TEMP TABLE foo (new1 text, new2 int);
SELECT ...