2012-04-24 9 views
16

Czy jest możliwe określenie wartości domyślnej, która zostanie zwrócona w przypadku niepowodzenia operacji CAST?Postgres: zdefiniować domyślną wartość awarii CAST?

Na przykład tak, że:

SELECT CAST('foo' AS INTEGER) 

zwróci wartość domyślną zamiast rzucania błąd?

+0

Zmiana domyślnego/oczekiwanego zachowania w ten sposób wydaje mi się ... niebezpieczna. Chcesz mieć możliwość sprawdzenia wartości za pomocą czegoś takiego jak 'IS_NUMERIC()' (funkcja SQL Server), ale wydaje się, że nie istnieje dla PostgreSQL (lub DB2, w moim przypadku). Najprawdopodobniej najlepiej by było, gdybyś utworzył UDF, do którego możesz również podać domyślną wartość. –

+0

Och, nie chcę zmieniać funkcjonalności - po prostu zdefiniuj domyślną dla tej obsady (np. Coś takiego jak 'CAST ('foo' AS INTEGER DEFAULT -1)' lub coś takiego –

Odpowiedz

22

Nie ma wartości domyślnej dla CAST:

typ obsada określa konwersję z jednego typu danych na inny. PostgreSQL przyjmuje dwa odpowiadające na składnie typu odlewów:

CAST (expression AS type) 
expression::type 

nie ma miejsca w składni do niczego innego niż ekspresji być odlewana i żądanego typu docelowego.

Jednak można to zrobić ręcznie za pomocą prostej funkcji:

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; 

Wtedy można powiedzieć takie rzeczy jak cast_to_int('pancakes', 0) i dostać 0.

PostgreSQL pozwala ci również create your own casts więc można robić takie rzeczy jak to:

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); 

Wtedy można powiedzieć

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

i dostać 0 czy można powiedzieć

select cast(some_text_column as integer) from t 

i uzyskać 0 dla some_text_column wartości, które nie są poprawnymi liczbami całkowitymi.Jeśli chciał rzucić varchar s przy użyciu tej auto-cast zalegających wtedy trzeba by podwójnej obsadzie:

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

Tylko dlatego, że można zrobić to nie sprawia, że ​​to dobry pomysł. Nie sądzę, aby zastąpienie standardowego tekstu całkowitym rzutem było najlepszym pomysłem. Powyższe podejście wymaga również, abyś sam rzucił standard, mógłbyś sobie z tym poradzić, gdybyś sam wykonał całą konwersję zamiast leniwie puntować do wbudowanego odlewu.

NULL obsługa jest pozostawiona jako (łatwe) ćwiczenie dla czytelnika.

+0

Zastanawiasz się, czy możesz wyjaśnić "* Zwróć uwagę na podwójny rzut, aby uniknąć nieskończonej rekursji * "? Myślałem, że' $ 1' jest już typu 'text/varchar' tam. – Bruno

+1

@Bruno: Funkcja to' cast_to_int (text) ', więc' $ 1' będzie ' text', 'text' i' varchar' są różnymi typami .Jeśli nie '$ 1 :: varchar', to robimy' cast (text as integer) '. Ale obsada jest zaimplementowana przez' cast_to_int 'function więc' cast_to_int' skończyłoby się pośrednio wywoływaniem przez niestandardową obsadę –

+1

Ach, co ciekawe, błędnie założyłem, że 'text' i' varchar' będą mniej więcej tym samym (http: // stackoverflow .com/a/4849030/372643) tam też, ale oczywiście nie. – Bruno

2

Przełknij błąd zgodnie z opisem w dokumentacji, a następnie określ czynności do wykonania.

Documentation on error trapping for PostgreSQL Snippet included included.

35.7.5. Błędy pułapkowania

Domyślnie każdy błąd występujący w funkcji PL/pgSQL powoduje przerwanie wykonywania funkcji, a także samej transakcji. Możesz przechwycić błędy i odzyskać je, używając bloku BEGIN z klauzulą ​​EXCEPTION. Składnia jest rozszerzeniem normalnej składni dla bloku BEGIN:

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

Jeśli wystąpi żaden błąd, ta forma bloku po prostu wykonuje wszystkie instrukcje, a następnie kontrola przechodzi do następnej instrukcji po END. Ale jeśli wystąpi błąd w instrukcjach, dalsze przetwarzanie instrukcji jest porzucane, a kontrola przechodzi do listy WYJDŹ. Lista jest przeszukiwana pod kątem pierwszego warunku odpowiadającego wystąpieniu błędu. Jeśli zostanie znalezione dopasowanie, zostaną wykonane odpowiednie instrukcje handler_statements, a następnie sterowanie przejdzie do następnej instrukcji po END. Jeśli nie zostanie znalezione dopasowanie, błąd rozprzestrzenia się tak, jakby klauzula EXCEPTION w ogóle nie istniała: błąd może zostać przechwycony przez blok otaczający za pomocą opcji EXCEPTION lub, jeśli nie istnieje, przerwać przetwarzanie tej funkcji.

Powiązane problemy