2

有没有办法根据一个条件生成多于一列?我的看法是这样的:

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

但是在复杂的情况下,这会变成一个很长的语句列表。

4

1 回答 1

2

你必须尝试一种完全不同的方法。其中之一

CTE LEFT JOIN//UNION ALL

  1. 选择CTE中第一个案例的所有列。
  2. 从第二种情况中排除已选择的行。
  3. 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 ...
于 2013-06-08T18:27:54.890 回答