PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come salvare un dato con una virgola di carattere variabile che passa attraverso un trigger?

Puoi usare format() per rendere la creazione di una query SQL dinamica molto più semplice in quanto gestirà automaticamente gli identificatori e i valori letterali correttamente. Una cosa che di solito le persone trascurano è che puoi espandere una singola espressione di record a tutte le sue colonne usando (...).* - funziona anche per NEW e OLD registrare le variabili in un trigger, ad es. select (new).*

Puoi anche passare variabili a un SQL dinamico con using parola chiave del execute dichiarazione. Non è necessario convertire il record avanti e indietro tra un record e una rappresentazione testuale.

Usando questa possibilità, la tua funzione di attivazione può essere semplificata in:

DECLARE 
  l_sql text;
BEGIN
    IF TG_TABLE_SCHEMA = 'public' THEN
      newtable := TG_TABLE_NAME || '_actividad';
    ELSE
      newtable := TG_TABLE_SCHEMA || '_' || TG_TABLE_NAME || '_actividad';
    END IF;

    PERFORM creartablaactividad(TG_TABLE_SCHEMA, TG_TABLE_NAME);
    l_sql := 'INSERT INTO actividad.%I  SELECT current_user, current_timestamp, %L, ($1).*';

    IF TG_OP = 'DELETE' THEN
      execute format(l_sql, newtable, 'D') using OLD;
      RETURN OLD;
    ELSE
      -- covers UPDATE and INSERT
      execute format(l_sql, newtable, 'U') using NEW;
      RETURN NEW;
    END IF;

    RETURN NULL; -- result is ignored since this is an AFTER trigger
END;

Utilizzo di segnaposto come %I e %L consente inoltre di definire l'SQL effettivo una sola volta e di riutilizzarlo. Questi "parametri" sono sostituiti da format() funzione (che conserva il $1 )

Nota l'uso di ($1).* all'interno della stringa SQL. Ciò farà execute istruzione espandi il parametro del record $1 a tutte le sue colonne. Il record stesso viene passato "nativamente" con il USING parola chiave.

L'uso di INSERT senza un elenco di colonne di destinazione (insert into some_table ... invece di insert into some_table (col1, col2, ...) ... ) è una cosa piuttosto fragile da fare. Se l'origine e la destinazione non corrispondono, l'inserimento può fallire abbastanza facilmente. .

Se non esegui report di massa sulle tabelle di controllo (dove avere nomi di colonna espliciti sarebbe molto più efficiente), potresti pensare a un trigger di controllo più generico utilizzando un JSON o HSTORE colonna per memorizzare l'intero record. Sono disponibili diversi trigger di audit già pronti: