Ini adalah temuan yang menarik. Biasanya, NULL tidak memiliki tipe data yang diasumsikan, seperti yang Anda lihat di sini:
SELECT pg_typeof(NULL);
pg_typeof
───────────
unknown
Ini berubah ketika sebuah VALUES
tabel muncul dalam gambar:
SELECT pg_typeof(core) FROM (
VALUES (NULL)
) new_values (core);
pg_typeof
───────────
text
Perilaku ini dijelaskan dalam kode sumber di 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.
*/
(Ya, kode sumber PostgreSQL relatif mudah dipahami dan sebagian besar tempat, berkat komentar yang sangat baik.)
Namun, jalan keluarnya mungkin sebagai berikut. Katakanlah Anda selalu membuat VALUES
yang cocok dengan semua kolom dari tabel yang diberikan (lihat catatan kedua di bawah untuk kasus lain). Dari contoh Anda, trik kecil mungkin dapat membantu:
SELECT (x).* FROM (VALUES ((TRUE, NULL, 1234)::fields)) t(x);
active │ core │ id
────────┼──────┼──────
t │ │ 1234
Di sini Anda menggunakan ekspresi baris yang dibuat untuk tipe tabel, dan kemudian mengekstraksinya kembali ke tabel.
Berdasarkan hal di atas, Anda UPDATE
bisa terlihat seperti
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;
Catatan:
- Saya menghapus tanda kutip ganda untuk keterbacaan manusia yang lebih baik, tetapi Anda dapat menyimpannya karena membantu ketika menghasilkan nama (kolom).
- jika Anda hanya membutuhkan sebagian dari kolom, Anda dapat membuat tipe khusus untuk tujuan ini. Gunakan mereka dengan cara yang sama seperti yang Anda lakukan di atas (di mana saya menggunakan jenis yang secara otomatis dibuat dengan tabel, memegang struktur baris yang terakhir).
Lihatlah semuanya bekerja pada dbfiddle .
Cannot cast type boolean to bigint in column 1
(titik kesalahan di :: antara pernyataan bidang pertama)