2012-04-24 10 views
16

¿Es posible definir un valor predeterminado que se devolverá en caso de que falle una operación CAST?Postgres: ¿define un valor predeterminado para las fallas de CAST?

Por ejemplo, de manera que:

SELECT CAST('foo' AS INTEGER) 

devolverá un valor por defecto en lugar de tirar un error?

+0

Cambiar el comportamiento predeterminado/esperado de esta manera me parece ... peligroso. Desea la capacidad de verificar el valor con algo como 'IS_NUMERIC()' (función del Servidor SQL), pero no parece existir para Postgresql (o DB2, en mi caso). Probablemente lo mejor sería crear una UDF, a la que también podría asignarle un valor predeterminado. –

+0

Oh, no quiero cambiar la funcionalidad, simplemente defina un valor predeterminado para ese molde (por ejemplo, algo así como 'CAST ('foo' AS INTEGER DEFAULT -1)' o algo. –

Respuesta

22

no hay ningún valor predeterminado para un CAST:

Un tipo fundido especifica una conversión de un tipo de datos a otro. PostgreSQL acepta dos sintaxis equivalentes para conversiones de tipo:

CAST (expression AS type) 
expression::type 

No hay lugar en la sintaxis para otra cosa que la expresión nada para ser fundido y el tipo de destino deseado.

Sin embargo, puede hacerlo a mano con una función simple:

create or replace function cast_to_int(text, integer) returns integer as $$ 
begin 
    return cast($1 as integer); 
exception 
    when invalid_text_representation then 
     return $2; 
end; 
$$ language plpgsql immutable; 

entonces se puede decir cosas como cast_to_int('pancakes', 0) y obtener 0.

PostgreSQL también le permite create your own casts por lo que podría hacer cosas como esta:

create or replace function cast_to_int(text) returns integer as $$ 
begin 
    -- Note the double casting to avoid infinite recursion. 
    return cast($1::varchar as integer); 
exception 
    when invalid_text_representation then 
     return 0; 
end; 
$$ language plpgsql immutable; 

create cast (text as integer) with function cast_to_int(text); 

Entonces se podría decir

select cast('pancakes'::text as integer) 

y obtener 0 o se podría decir

select cast(some_text_column as integer) from t 

y obtener 0 para el some_text_column valores que no son enteros válidos.Si quería echar varchar s utilizando esta auto-morosos fundido entonces habría que doble reparto:

select cast(some_varchar::text as integer) from t 

El hecho de que usted puede hacer esto no significa que sea una buena idea. No creo que reemplazar el texto estándar por un elenco entero sea la mejor idea de la historia. El enfoque anterior también requiere que dejes el estándar varchar en integer por separado, podrías evitarlo si quisieras hacer toda la conversión tú mismo en lugar de pedalear perezosamente al casting integrado.

El manejo NULL se deja como un ejercicio (fácil) para el lector.

+0

Solo me preguntaba si podría aclarar "* Tenga en cuenta el doble casting para evitar la recursión infinita * "? Hubiera pensado que' $ 1' ya era de tipo 'text/varchar' allí. – Bruno

+1

@Bruno: La función es' cast_to_int (text) 'por lo que' $ 1' será ' text', 'text' y' varchar' son tipos diferentes. Si no hiciéramos '$ 1 :: varchar' entonces estaríamos haciendo un' molde (texto como entero) '. Pero ese molde es implementado por' cast_to_int 'function por lo que' cast_to_int' terminaría llamándose indirectamente a través del molde personalizado. –

+1

Ah, es interesante, estaba asumiendo erróneamente que 'text' y' varchar' serían [más o menos lo mismo] (http: // stackoverflow .com/a/4849030/372643) también, pero obviamente no. – Bruno

2

Detecta el error como se describe en la documentación y luego especifica una acción para hacer.

Documentation on error trapping for PostgreSQL Fragmento incluido a continuación.

35.7.5. Errores de reventado

De forma predeterminada, cualquier error que se produzca en una función PL/pgSQL anula la ejecución de la función y, de hecho, también de la transacción circundante. Puede atrapar errores y recuperarse de ellos utilizando un bloque BEGIN con una cláusula EXCEPTION. La sintaxis es una extensión de la sintaxis normal para un bloque BEGIN:

[ <<label>> ] 
[ DECLARE 
    declarations ] 
BEGIN 
    statements 
EXCEPTION 
    WHEN condition [ OR condition ... ] THEN 
     handler_statements 
    [ WHEN condition [ OR condition ... ] THEN 
      handler_statements 
     ... ] 
END; 

Si no se produce ningún error, esta forma de bloque simplemente ejecuta todas las declaraciones, y entonces el control pasa a la siguiente instrucción después de END. Pero si ocurre un error dentro de las declaraciones, se abandona el procesamiento posterior de las declaraciones y el control pasa a la lista EXCEPCIÓN. En la lista se busca la primera condición que coincida con el error que ocurrió. Si se encuentra una coincidencia, se ejecutan las instrucciones handler_correctantes correspondientes, y luego el control pasa a la siguiente instrucción después de END. Si no se encuentra ninguna coincidencia, el error se propaga como si la cláusula EXCEPTION no estuviera allí: el error puede ser capturado por un bloque envolvente con EXCEPCIÓN o, si no hay ninguno, anula el procesamiento de la función.

Cuestiones relacionadas