Trigger with dynamic field name

后端 未结 3 571
别跟我提以往
别跟我提以往 2020-12-19 09:35

I have a problem on creating PostgreSQL (9.3) trigger on update table. I want set new values in the loop as

EXECUTE \'NEW.\'|| fieldName || \':=\'\'some prep         


        
相关标签:
3条回答
  • 2020-12-19 10:05

    I found a working solution: trigger should execute after insert/update, not before. Then desired row takes the form

    EXECUTE 'UPDATE ' || TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME ||
                    ' SET ' || fieldName || '= ''prefix:'' ||''' || fieldValue || ''' WHERE id = ' || NEW.id;
    

    fieldName and fieldValue I get in the next way:

    FOR fieldName,fieldValue IN select key,value from each(hstore(NEW)) LOOP
           IF .... THEN
    END LOOP:
    
    0 讨论(0)
  • 2020-12-19 10:17

    Your problem is that EXECUTE can only be used to execute SQL statements and not PL/pgSQL statements like the assignment in your question.

    You can maybe work around that like this:

    Let's assume that table testtab is defined like this:

    CREATE TABLE testtab (
       id integer primary key,
       val text
    );
    

    Then a trigger function like the following will work:

    BEGIN
       EXECUTE 'SELECT $1.id, ''prefix '' || $1.val' INTO NEW USING NEW;
       RETURN NEW;
    END;
    

    I used hard-coded idand val in my example, but that is not necessary.

    0 讨论(0)
  • 2020-12-19 10:28

    You can implement that rather conveniently with the hstore operator #=:

    Make sure the additional module is installed properly (once per database), in a schema that's included in your search_path:

    • How to use % operator from the extension pg_trgm?
    • Best way to install hstore on multiple schemas in a Postgres database?

    Trigger function:

    CREATE OR REPLACE FUNCTION tbl_insup_bef()
      RETURNS TRIGGER AS
    $func$
    DECLARE
       _prefix CONSTANT text := 'some prepend data'; -- your prefix here
       _prelen CONSTANT int  := 17;  -- length of above string (optional optimization)
       _col text := quote_ident(TG_ARGV[0]);
       _val text;
    BEGIN
       EXECUTE 'SELECT $1.' || _col
       USING NEW
       INTO _val;
    
       IF left(_val, _prelen) = _prefix THEN 
          -- do nothing: prefix already there!
       ELSE
          NEW := NEW #= hstore(_col, _prefix || _val);  
       END IF;
    
       RETURN NEW;
    END
    $func$  LANGUAGE plpgsql;
    

    Trigger (reuse the same func for multiple tables):

    CREATE TRIGGER insup_bef
    BEFORE INSERT OR UPDATE ON tbl
    FOR EACH ROW
    EXECUTE PROCEDURE tbl_insup_bef('fieldName');  -- unquoted, case-sensitive column name
    

    Closely related with more explanation and advice:

    • Assignment of a column with dynamic column name
    • How to access NEW or OLD field given only the field's name?
    • Get values from varying columns in a generic trigger
    0 讨论(0)
提交回复
热议问题