これは興味深い発見です。次のように、通常、NULLには想定されたデータ型はありません。
SELECT pg_typeof(NULL);
pg_typeof
───────────
unknown
これは、VALUES
テーブルが画像に入ると変化します。
SELECT pg_typeof(core) FROM (
VALUES (NULL)
) new_values (core);
pg_typeof
───────────
text
この動作は、https://doxygen.postgresql.org/parse__coerce_8c.html#l01373のソースコードで説明されています。
/*
* If all the inputs were UNKNOWN type --- ie, unknown-type literals ---
* then resolve as type TEXT. This situation comes up with constructs
* like SELECT (CASE WHEN foo THEN 'bar' ELSE 'baz' END); SELECT 'foo'
* UNION SELECT 'bar'; It might seem desirable to leave the construct's
* output type as UNKNOWN, but that really doesn't work, because we'd
* probably end up needing a runtime coercion from UNKNOWN to something
* else, and we usually won't have it. We need to coerce the unknown
* literals while they are still literals, so a decision has to be made
* now.
*/
(はい、PostgreSQLのソースコードは、優れたコメントのおかげで、ほとんどの場所で比較的理解しやすくなっています。)
ただし、解決策は次のようになります。VALUES
特定のテーブルのすべての列に一致するものを常に生成しているとしましょう(他のケースについては、下の2番目のメモを参照してください)。あなたの例から、小さなトリックがおそらく役立つかもしれません:
SELECT (x).* FROM (VALUES ((TRUE, NULL, 1234)::fields)) t(x);
active │ core │ id
────────┼──────┼──────
t │ │ 1234
ここでは、テーブルの型にキャストされた行式を使用し、それを抽出してテーブルに戻します。
以上を踏まえ、あなたはUPDATE
次のようになり
UPDATE fields AS t set active = (x).active, core = (x).core
FROM ( VALUES
((true, NULL, 3419)::fields),
((false, NULL, 3420)::fields)
) AS new_values(x) WHERE (x).id = t.id;
ノート:
- 人間が読みやすいように二重引用符を削除しましたが、(列)名を生成するときに役立つので、そのままにしておくことができます。
- 列のサブセットのみが必要な場合は、この目的でカスタムタイプを作成できます。上記と同じように使用します(テーブルで自動的に作成された型を使用し、後者の行構造を保持します)。
dbfiddleで作業している全体を見てください。
Cannot cast type boolean to bigint in column 1
(最初のフィールドステートメント間の::のエラーポイント)