Este es un hallazgo interesante. Normalmente, un NULL no tiene un tipo de datos asumido, como puede ver aquí:
SELECT pg_typeof(NULL);
pg_typeof
───────────
unknown
Esto cambia cuando una VALUES
tabla entra en escena:
SELECT pg_typeof(core) FROM (
VALUES (NULL)
) new_values (core);
pg_typeof
───────────
text
Este comportamiento se describe en el código fuente en 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.
*/
(Sí, el código fuente de PostgreSQL es relativamente fácil de entender y la mayoría de los lugares, gracias a los excelentes comentarios).
La salida, sin embargo, podría ser la siguiente. Supongamos que siempre está generando una VALUES
coincidencia con todas las columnas de una tabla determinada (consulte la segunda nota a continuación para ver otros casos). A partir de su ejemplo, un pequeño truco podría ayudar:
SELECT (x).* FROM (VALUES ((TRUE, NULL, 1234)::fields)) t(x);
active │ core │ id
────────┼──────┼──────
t │ │ 1234
Aquí usa expresiones de fila convertidas al tipo de tabla y luego las extrae de nuevo a una tabla.
Con base en lo anterior, UPDATE
podría verse como
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;
Notas:
- Eliminé las comillas dobles para una mejor legibilidad humana, pero puede mantenerlas ya que ayudan a generar nombres (columnas).
- Si solo necesita un subconjunto de las columnas, puede crear tipos personalizados para este propósito. Úselos de la misma manera que lo haría anteriormente (donde uso el tipo creado automáticamente con la tabla, manteniendo la estructura de filas de este último).
Mira todo el trabajo en dbfiddle .
Cannot cast type boolean to bigint in column 1
(el error apunta a :: entre la declaración de los primeros campos)