Casting NULL Type in Multi-Row Updates
In PostgreSQL, executing an update query on multiple rows can lead to errors when dealing with NULL values if the column types are not explicitly cast. This article explores several solutions to this issue, providing alternative approaches to ensure proper type casting during multi-row updates.
Solution 1: Select Limit 0 with VALUES and UNION ALL
UPDATE foo f SET x = t.x , y = t.y FROM ( (SELECT pkid, x, y FROM foo LIMIT 0) -- Get column types UNION ALL VALUES (1, 20, NULL) -- No type casts , (2, 50, NULL) ) t -- Column names and types defined WHERE f.pkid = t.pkid;
This method combines a SELECT statement with a LIMIT of 0 to retrieve column names and types and then appends the desired data rows using the UNION ALL operator. The first row of the subquery ensures that the appropriate column types are defined for the subsequent rows.
Solution 2: Select Limit 0 with VALUES and UNION ALL SELECT
UPDATE foo f SET x = t.x , y = t.y FROM ( (SELECT pkid, x, y FROM foo LIMIT 0) -- Get column types UNION ALL SELECT 1, 20, NULL UNION ALL SELECT 2, 50, NULL ) t -- Column names and types defined WHERE f.pkid = t.pkid;
Similar to Solution 1, this approach uses SELECT to get column types and then uses individual SELECT statements to append data rows, preventing any premature type casting.
Solution 3: VALUES Expression with Per-Column Type
UPDATE foo f SET x = t.x , y = t.y FROM ( VALUES ((SELECT pkid FROM foo LIMIT 0) , (SELECT x FROM foo LIMIT 0) , (SELECT y FROM foo LIMIT 0)) -- Get type for each col individually , (1, 20, NULL) , (2, 50, NULL) ) t (pkid, x, y) -- Columns names not defined yet, only types. ...
This solution defines the column types within the VALUES expression itself, ensuring that the subsequent rows are cast to those types without encountering any errors due to automatic type assumptions.
Solution 4: VALUES Expression with Row Type
UPDATE foo f SET x = (t.r).x -- Parenthesis for unambiguous syntax , y = (t.r).y FROM ( VALUES ('(1,20,)'::foo) -- Columns need to be in table default order ,('(2,50,)') -- Nothing after last comma for NULL ) t (r) -- Column name for row type WHERE f.pkid = (t.r).pkid;
This approach uses the row type of the specific table, allowing you to cast columns to the correct types implicitly. You can access individual column values using field selection syntax.
Solution 5: VALUES Expression with Decomposed Row Type
UPDATE foo f SET x = t.x , y = t.y FROM ( VALUES (('(1,20,)'::foo).*) -- Decomposed row of values , (2, 50, NULL) ) t(pkid, x, y) -- Arbitrary column names (match table columns) WHERE f.pkid = t.pkid; -- Eliminates 1st row with NULL values
Similar to Solution 4, but using decomposed rows to specify data values. This allows you to provide only the relevant columns, eliminating the need to know the complete order and types of all columns in the table.
Choosing the best solution depends on factors such as performance, convenience, and the availability of information about column types.
The above is the detailed content of How to Handle NULL Type Casting in PostgreSQL Multi-Row Updates?. For more information, please follow other related articles on the PHP Chinese website!