![]() | |
![]() |
| | Thread Tools | Display Modes |
#1
| |||
| |||
|
#2
| |||
| |||
|
|
Hello, I have a weird question, is there a way to perform a query on a table which the name is been obtaind from another query? A trivial example with no practical purpose invented to show what I mean: create or replace function test(_schema varchar) returns bigint as $$ declare var_table_name record; totalcount bigint; begin totalcount:=0; for var_table_name in select table_name from information_schema.tables where table_schema=_schema loop totalcount := totalcount + select count(*) from var_table_name; end loop; return totalcount; end; $$ language plpgsql; is there a way to interpolate, for example var_table_name? |
#3
| |||
| |||
|
|
Sure, you have to use EXECUTE for dynamic SQL. http://www.postgresql.org/docs/curre...-EXECUTING-DYN Andreas |
| V |
|
| 'trigger after delete or update or insert on ' || t.table_schema || '.' || t.table_name || ' execute procedure update_matview(' || |
#4
| |||
| |||
|
|
Ops, I am sorry, I got confused and put the wrong question, my need is actually to dynamically generate a query with values retrieved from OLD and NEW record variables in a trigger, something like this: the probelmatic point: | | V r_d_table := rtable || ' and ' || col || '=' OLD.<col?> ; r_i_table := rtable || ' and ' || col || '=' NEW.<col?> ; |
#5
| |||
| |||
|
|
There is a good page on this in the PostgreSQL Wiki: http://wiki.postgresql.org/wiki/PL/p...namic_Triggers I got the example working like this: CREATE OR REPLACE FUNCTION printnew() RETURNS trigger LANGUAGE plpgsql AS $$DECLARE ri RECORD; t TEXT; BEGIN RAISE NOTICE E'\n Operation: %\n Schema: %\n Table: %', TG_OP, TG_TABLE_SCHEMA, TG_TABLE_NAME; FOR ri IN SELECT ordinal_position, column_name, data_type FROM information_schema.columns WHERE table_schema = quote_ident(TG_TABLE_SCHEMA) AND table_name = quote_ident(TG_TABLE_NAME) ORDER BY ordinal_position LOOP EXECUTE 'SELECT (' || quote_literal(NEW) || '::' || TG_RELID::regclass || ').' || quote_ident(ri.column_name) INTO t; RAISE NOTICE E'Column\n number: %\n name: %\n type: %\n value: %.', ri.ordinal_position, ri.column_name, ri.data_type, t; END LOOP; RETURN NEW; END;$$; This should give you an idea how you could achieve your goal. Yours, Laurenz Albe |
many thanks for smart advices!
#6
| |||
| |||
|
|
about the materialized views, I am thinking to use OIDs instead of comparing all the columns values between NEW/OLD records and original table, perhaps it could be more direct/fast but dunno if NEW and OLD contains OID row. What do you think about? |
#7
| |||
| |||
|
|
Just for curiosity I tried to look at the examples in the wiki too, and did not understand this statement: EXECUTE 'SELECT ($1).' || ri.column_name || '::text' INTO t USING NEW; I dont know what "($1)" means and did not find the clause "using" in the execute statement: http://www.postgresql.org/docs/curre...-EXECUTING-DYN |
|
about the materialized views, I am thinking to use OIDs instead of comparing all the columns values between NEW/OLD records and original table, perhaps it could be more direct/fast but dunno if NEW and OLD contains OID row. What do you think about? |
#8
| |||
| |||
|
|
Yes, that is because this is a new feature in 8.4 (as the Wiki says). It is a dynamic statement with parameters, and what happens is that the first placeholder $1 gets replaced with the value in NEW, which is a record type. Then the appropriate column is picked out, and the result is cast to "text". about the materialized views, I am thinking to use OIDs instead of comparing all the columns values between NEW/OLD records and original table, perhaps it could be more direct/fast but dunno if NEW and OLD contains OID row. What do you think about? As you realized, depending on OIDs is not a good idea. I don't understand why you want to compare the values in NEW with other rows in the original table, perhaps I don't understand your design well enough. Isn't it that you want to write a materialized view that is updated whenever something on the underlying table changes? In that case I would expect that you only need to access the materialized view to change rows in it appropriately. And if you ensure that you have a useful primary key on the materialized view table, these operations should be fast, right? |
|
| quote_ident(_view_name) || ')'; execute qry; |

#9
| |||
| |||
|
#10
| |||
| |||
|
|
I don't understand why you want to compare the values in NEW with other rows in the original table, perhaps I don't understand your design well enough. [...] right, I was trying to write something generalized to tables without a primary key. Actually tables without primary key are usually found in bad designed databases, so it would be reasonable to admit that tables have always primary keys. I'll explain better what I am trying to do in my very little spare time. I can automatically create a trigger for eache table involved in the view I want to materialize: create or replace function create_matview |
|
the next step it is to retrieve the records of the view affected by the change, and only those, so I should put in join every record of the trigger with the view, the trick here (very very dirty) it is to retrieve the definition of the view: and then replace the name of the table the trigger has been fired from with a subquery involving only the record changed, it should work only under the condition that views to be materialized MUST use aliases and only aliases for ALL the tables in definition, below an _idea_ of trigger code: [...] what do you think about such a tricky thing?, I know it is a big mess with big limitations (must use aliases for all the tables in views, it does not work for views upon views, etc etc) but I would like to get it working ![]() |
![]() |
| Thread Tools | |
| Display Modes | |
| |