[英]PostgreSQL UPDATE trigger on SELECT using IF/ELSE statements
[英]Using FOR LOOP and IF Statements to UPDATE a Column in Postgresql
我需要在同一個表中使用列 'a_sp' (varchar) 更新列 'sp' (varchar)。 兩列都包含從零/空到多個值列表。 這些值與“+”號連接,並與該符號一起存儲在它的開頭和結尾。 我想遍歷'a_sp'中的每個值並檢查它是否已經存在於其各自的'sp'單元格中。 如果是,則不會將任何內容附加到“sp”,如果不是,則附加該值。 感謝您的幫助,因為我剛剛從 OOP 適應數據庫編程。
UPDATE work.table
SET sp =
CASE
WHEN (sp IS NULL OR sp = '') THEN a_sp --no sp val return a_sp
WHEN (sp IS NOT NULL OR sp != '') THEN --if there exists sp val
CASE
WHEN sp LIKE '%'||a_sp||'%' THEN sp --if existing sport val is similar to a_sp return sp
ELSE sp||ltrim(a_sp, '+') --if existing sp val not similar to asp, append
END
ELSE sp --if both cases above not met (which is odd) return sp
END
WHERE a_sp IS NOT NULL;
我的解決方案(雖然俗氣) -
--I found the function (below) which creates a distinct array of any array type at https://postgres.cz/wiki/Array_based_functions
CREATE OR REPLACE FUNCTION work.array_distinct(anyarray)
RETURNS anyarray AS $$
SELECT ARRAY(SELECT DISTINCT unnest($1))
$$ LANGUAGE sql;
--for sp col
UPDATE work.tab
SET sp =
CASE
WHEN (sp IS NULL OR sp = '') THEN a_sp --no sp val return a_sp
WHEN (sp IS NOT NULL OR sp != '') THEN
--below i did quite some manipulations
--i removed the '+' to the left of a_sp column
--then concatenated sp and asp columns
--i converted the concatenated result to array based on the string '+' as a divider
--next, i used the function 'array_distinct' above to return unique values # this was quite a way to avoid looping through the lists to append
--i converted the result above back to string with a string '+' separator
--i finally added string '+' to both ends of my result
replace(replace('+'||rtrim(array_to_string(array_distinct(regexp_split_to_array(replace(sp||ltrim(a_sp, '+'), '+', ' '), E'\\s+')::varchar[]), ','), ',')||'+',',', '+'), '++', '+') --if there exists sp val
--ELSE sport --if both cases above not met (which is odd) return sp
END
WHERE a_sp IS NOT NULL;
我假設您的代碼有效,而您只是在尋找更好的方法。 在你正在做的單個更新語句中而不是在循環中執行它絕對是 go 的方式,因為它比循環快光年。
您的代碼可能會以更好的方式編寫,減少冗余檢查和不需要更新的更新:
UPDATE work.table
SET sp = CASE WHEN NULLIF(sp, '') IS NULL THEN a_sp ELSE sp || ltrim(a_sp, '+') END
WHERE a_sp IS NOT NULL
AND COALESCE(sp, '') !~ a_sp -- don't perform unnecessary updates
您的 CASE 語句可以稍微簡化 - 如果sp
為 NULL/空,請將其設置為a_sp
,否則將其與a_sp
。 並且添加到WHERE
子句中會過濾掉不應更新的情況( sp
包含在a_sp
中)。
編輯:
sp LIKE '%'||a_sp||'%'
不會像您期望的那樣工作,因為它將通配符放在整個a_sp
字段的末尾,因此它不會找到a_sp
值包含sp
的情況substring。 因此,正則表達式是一種簡單的檢查方法,但您也可以通過position
function 進行檢查,這就像其他語言中的indexOf
:
WHERE ...
AND (NULLIF(sp, '') IS NULL OR POSITION(sp IN a_sp) = 0) -- i.e. a_sp does not contain sp
因為POSITION('' IN 'x')
為 1,所以在檢查中添加了NULLIF
,但我們不想排除 NULL/空sp
行。
編輯2:
我現在明白你想要做什么了。 我認為這只是檢查sp
的值是否在a_sp
中,如果是,則忽略,如果不是,則連接字段。 但實際上每個字段都包含分隔數據,因此需要將每個字段的數據有效地拆分為多個部分,然后將兩個字段的不同部分重新組合並寫入sp
字段。 這實際上是您在解決方案中所做的。 我將在下面再次提出一種稍微不同的方法。
我也明白為什么正則表達式不起作用,這是由於字段中的+
符號。 無論如何,鑒於我現在對您正在嘗試做的事情的理解,它不再是一種有效的檢查方式。
設置
CREATE TABLE t (id INTEGER, sp TEXT, a_sp TEXT);
INSERT INTO t
VALUES
(1, '+hk1+', '+rk3+hk1+xk5+'),
(2, '+hk1+hk2+', '+jk8+hk1+'),
(3, NULL, '+hk1+dk7+'),
(4, '', '+hk1+dk7+'),
(5, '+hk3+', NULL),
(6, '+hk2+', '+hk1+');
詢問
UPDATE t
SET sp = (
SELECT '+' || STRING_AGG(DISTINCT u, '+' ORDER BY u) || '+'
FROM UNNEST(string_to_array(sp, '+', '') || string_to_array(a_sp, '+', '')) u
WHERE u IS NOT NULL
)
WHERE a_sp IS NOT NULL;
結果(更新運行后的SELECT * FROM t
)
| id | sp | a_sp |
| --- | ------------- | ------------- |
| 1 | +hk1+rk3+xk5+ | +rk3+hk1+xk5+ |
| 2 | +hk1+hk2+jk8+ | +jk8+hk1+ |
| 3 | +dk7+hk1+ | +hk1+dk7+ |
| 4 | +dk7+hk1+ | +hk1+dk7+ |
| 5 | +hk3+ | |
| 6 | +hk1+hk2+ | +hk1+ |
子查詢:
+
分隔符拆分兩個字段。 你也可以使用regexp_split_to_array
但我決定 go 和string_to_array
因為我可以將''
設置為 NULL (第三個參數)。並將結果寫入sp
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.