![](/img/trans.png)
[英]SELECT with lower case + unaccent + multiple columns in PostgreSQL
[英]Using CASE in PostgreSQL to affect multiple columns at once
我有一個帶有這些表達式的 Postgres SELECT
語句:
,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
是否為真。 我一遍又一遍地重復具有相同條件的CASE
語句。
有什么方法可以組合這些CASE
表達式來一次性切換多列的輸出?
LEFT JOIN
單行值您可以使用條件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
由單行組成,因此無需其他條件就可以進行連接。
子查詢中需要顯式類型轉換。 我在示例中使用text
(無論如何這是字符串文字的默認值)。 使用您的實際數據類型。 語法快捷方式value::type
是 Postgres 特定的,對標准 SQL 使用cast(value AS type)
。
如果條件不是TRUE
,則x
中的所有值都是 NULL,並且COALESCE
開始。
或者,由於在您的特定情況下所有候選值都來自表rtd2
, rtd2
使用原始CASE
條件將LEFT JOIN
到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'::text AS txt2
, 'test example #2'::text AS txt3
) x;
這取決於連接條件和查詢的其余部分。
如果您的各個列共享相同的數據類型,您可以在子查詢中使用數組並在外部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;
如果列不共享相同的數據類型,它會變得更加復雜。 您可以將它們全部轉換為text
(並可選擇在外部SELECT
轉換回來),或者您可以...
您可以使用自定義復合類型(行類型)來保存各種類型的值,並在外部SELECT
簡單地 *-expand 。 假設我們有三列: text
、 integer
和date
。 為了重復使用,創建一個自定義的復合類型:
CREATE TYPE my_type (t1 text, t2 int, t3 date);
或者,如果現有表的類型匹配,您可以只使用表名作為復合類型。
或者,如果您只需要臨時類型,您可以創建一個TEMPORARY TABLE
,它會在您的會話期間注冊一個臨時類型:
CREATE TEMP TABLE my_type (t1 text, t2 int, t3 date);
您甚至可以為單個事務執行此操作:
CREATE TEMP TABLE my_type (t1 text, t2 int, 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', 3, now()::date)::my_type
ELSE (r2.team_name, r2.int_col, r2.date_col)::my_type
END).*
FROM rtp
JOIN rtd2 r2 ON <unknown condition>;
CASE
表達式以這種方式為每一列計算一次。 如果評估不是微不足道的,帶有子查詢的另一個變體會更快。
不確定這是否會有所改進,但您可以以另一種方式將SELECT
與自身聯合:
SELECT
...,
'testing' AS testing_testing,
'test example' AS test_response,
'test example #2' AS another_example, ...
FROM ...
WHERE rtp.team_id = rtp.sub_team_id AND ...
UNION
SELECT
...,
TRIM(rtd2.team_name) AS testing_testing,
TRIM(rtd2.normal_data) AS test_response,
TRIM(rtd2.normal_data_2) AS another_example, ...
WHERE rtp.team_id <> rtp.sub_team_id AND ...;
列名可以安全地從第二個查詢中省略,假設您以與第一個相同的順序顯示它們。
您可能希望使用公共表表達式 (CTE) 將其中的每一個作為單獨的查詢。 如果您擔心這會更改順序,您可以將其設為子查詢並在其周圍應用ORDER BY
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.