2 years ago

#49048

test-img

Chad S

How to update all constraints referencing some field? For loop execute plpgsql

I want to update several constraints to cascade on delete or update. I know there are going to be major changes to "field_z" in "my_table", and many other fields in my database are foreign keys referencing "field_z" thus I need them to update automatically. The following two lines of code solve the problem for one constraint.

ALTER TABLE some_table DROP CONSTRAINT some_table_field_z_fkey 
ALTER TABLE some_table ADD CONSTRAINT some_table_field_z_fkey FOREIGN KEY ('field_z') REFERENCES my_table ('field_z') ON DELETE CASCADE ON UPDATE CASCADE;

I need to update a large number of constraints. I'm using the code below to list all of the constraints and foreign keys tied to field_z in my_table.

CREATE TABLE temp_table AS (
select (select r.relname from pg_class r where r.oid = c.conrelid) as foreign_table, 
    (select attname from pg_attribute where attrelid = c.conrelid and ARRAY[attnum] <@ c.conkey) as foreign_col, 
    (select r.relname from pg_class r where r.oid = c.confrelid) as reference_table,
    (select conname from pg_class r where r.oid = c.confrelid) as cnstrnt_name
from pg_constraint c 
where c.confrelid = (select oid from pg_class where relname = 'my_table') and 
      c.confkey @> (select array_agg(attnum) from pg_attribute 
                    where attname = 'field_z' and attrelid = c.confrelid)
);

I'd like to iterate through each row of the temp_table created above and substitute the cell values into the two lines of code at the top of this post, as shown below:

DO $$
DECLARE temp_row temp_table%ROWTYPE;
BEGIN
    FOR temp_row in SELECT * FROM temp_table LOOP EXECUTE
        'ALTER TABLE ' || quote_ident(temp_row.foreign_table) || ' DROP CONSTRAINT ' || quote_ident(temp_row.cnstrnt_name) || ';'
        'ALTER TABLE ' || quote_ident(temp_row.foreign_table) || ' ADD CONSTRAINT ' || quote_ident(temp_row.cnstrnt_name) || 
        ' FOREIGN KEY (' || quote_ident(temp_row.foreign_col) || ') 
        REFERENCES ' || quote_ident(temp_row.reference_table) || ' (' || quote_literal(field_z) || ') 
        ON DELETE CASCADE ON UPDATE CASCADE;';
    END LOOP;
END; $$ LANGUAGE plpgsql;

The for loop does not work, it breaks with error 'type "quote_ident" does not exist.' My hypothesis is that I haven't set up my loop to correctly iterate through rows and access the cell values as table, field, or constraint names. This is the first time I've used programmatic sql so I could be far off the mark. Any help to fix this loop or suggestions for better methods is appreciated. Thanks.

postgresql

plpgsql

0 Answers

Your Answer

Accepted video resources