Konfiguracja
Chcesz utworzyć wyzwalacze (wielokrotnie?) Za pomocą tej samej funkcji wyzwalacza, jak opisano w moja powiązana odpowiedź na dba.SE . Musisz przekazać wartości do funkcji wyzwalacza, aby utworzyć wiele wiersze z wieloma wartości kolumn, stąd dwuwymiarowa tablica. (Ale możemy pracować z każdym wyraźnie zdefiniowany ciąg!)
Jedynym sposobem przekazania wartości do funkcji wyzwalającej PL/pgSQL (innej niż wartości kolumn w wierszu wyzwalającym) jest text
parametry, które są dostępne wewnątrz funkcji jako 0- oparta tablica tekstu w specjalnej zmiennej tablicowej TG_ARGV[]
. Możesz przekazać zmienną liczbę parametrów, ale omówiliśmy wcześniej pojedynczy literał ciągu reprezentujący twoją dwuwymiarową tablicę.
Dane wejściowe pochodzą z dwuwymiarowej tablicy Pythona z liczbą całkowitą ze znakiem liczby, które pasują do Postgresa typu integer
. Użyj Postgresa typu bigint
aby pokryć liczby całkowite bez znaku, jako skomentował
.
Reprezentacja tekstowa w Pythonie wygląda tak:
[[1,2],[3,4]]
Składnia literału tablicy Postgres:
{{1,2},{3,4}}
I chcesz zautomatyzować ten proces.
Pełna automatyzacja
Możesz połączyć ciąg dla CREATE TRIGGER
w swoim kliencie lub możesz utrwalić logikę w funkcji po stronie serwera i po prostu przekazać parametry.
Demonstracja przykładowej funkcji pobierającej nazwę tabeli i ciąg, który jest przekazywany do funkcji wyzwalacza. Funkcja wyzwalacza insaft_function()
jest zdefiniowany w poprzednim pytaniu na dba.SE
.
CREATE OR REPLACE FUNCTION f_create_my_trigger(_tbl regclass, _arg0 text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format($$
DROP TRIGGER IF EXISTS insaft_%1$s_ids ON %1$s;
CREATE TRIGGER insaft_%1$s_ids
AFTER INSERT ON %1$s
FOR EACH ROW EXECUTE PROCEDURE insaft_function(%2$L)$$
, _tbl
, translate(_arg0, '[]', '{}')
);
END
$func$;
Zadzwoń:
SELECT f_create_my_trigger('measurements', '[[1,2],[3,4]]');
Lub:
SELECT f_create_my_trigger('some_other_table', '{{5,6},{7,8}}');
db<>fiddle tutaj
Stary sqlfiddle
Teraz możesz przekazać albo [[1,2],[3,4]]
(z nawiasami kwadratowymi) lub {{1,2},{3,4}}
(z nawiasami klamrowymi). Obie działają tak samo. translate(_arg0, '[]', '{}'
przekształca pierwszą w drugą formę.
Ta funkcja usuwa wyzwalacz o tej samej nazwie, jeśli istnieje, przed utworzeniem nowego. Możesz zrezygnować lub zachować tę linię:
DROP TRIGGER IF EXISTS insaft_%1$s_ids ON %1$s;
Działa to z uprawnieniami wywołującej roli DB. W razie potrzeby możesz uruchomić go z uprawnieniami superużytkownika (lub dowolnymi innymi). Zobacz:
Istnieje wiele sposobów, aby to osiągnąć. To zależy od dokładnych wymagań.
Objaśnienie format()
format()
i typ danych regclass
pomagają bezpiecznie łączyć polecenie DDL i uniemożliwiają wstrzykiwanie SQL. Zobacz:
Pierwszym argumentem jest „ciąg formatu”, po którym następują argumenty, które mają zostać osadzone w ciągu. Używam cytowania dolarów
, co nie jest konieczne w tym przykładzie, ale ogólnie jest dobrym pomysłem na łączenie długich ciągów zawierających pojedyncze cudzysłowy:$$DROP TRIGGER ... $$
format()
jest wzorowany na funkcji C sprintf
. %1$s
jest specyfikatorem formatu format( )
funkcjonować. Oznacza to, że pierwszy (1$
) argument po wstawieniu ciągu formatu jako ciąg bez cudzysłowu (%s
), stąd:%1$s
. Pierwszym argumentem do formatowania jest _tbl
w przykładzie - regclass
parametr jest automatycznie renderowany jako prawidłowy identyfikator, w razie potrzeby w cudzysłowie, więc format()
nie musi robić więcej. Stąd po prostu %s
, a nie %I
(identyfikator). Przeczytaj odpowiedź z linkiem powyżej, aby uzyskać szczegółowe informacje.
Inny używany specyfikator formatu to %2$L
:Drugi argument jako cytowany literał ciągu .
Jeśli jesteś nowy w format()
, pobaw się tymi prostymi przykładami, aby zrozumieć:
SELECT format('input -->|%s|<-- here', '[1,2]')
, format('input -->|%s|<-- here', translate('[1,2]', '[]', '{}'))
, format('input -->|%L|<-- here', translate('[1,2]', '[]', '{}'))
, format('input -->|%I|<-- here', translate('[1,2]', '[]', '{}'));