postgresql update true if other table column having value else false - postgresql

I want to update tableA column as "True" if in tableB column having any value other wise update as false.
The updating process should done for all schema which is having this tables dynamically.
Please help me on this.
update TA set TA.col=true else false (if TB.col having any value)
DO $$
declare
l_rec record;
l_schema_name varchar(100);
l_sql varchar(100);
BEGIN
for rec in select Table_schema, table_name from information_schema.tables where table_name='table A' and 'table B'
LOOP
l_schema_name :=rec.Table_schema;
l_sql := 'update '||l_schema_name||'.TA Set TA.column1= (case when isnull(TB.Column,' ')=' ' then false else true end) From tableA TA left join tableB TB on TA.Col=TB.Col';
begin
execute l_sql;
end;
END loop;
END;
$$;

i have a solution for the above query.
DO $$
declare
rec record;
l_schema_name varchar(100);
l_sql varchar(1000);
BEGIN
for rec in select Table_schema, table_name from information_schema.tables
where table_name='TA' and table_schema='schema_name'
LOOP
l_schema_name :=rec.Table_schema;
l_sql := 'update '||l_schema_name||'.TableA TA set TA.col=true
where id in (select id from '||l_schema_name||'.Tableb TB)';
begin
execute l_sql;
Raise notice 'Updated for % :',l_schema_name;
end;
END loop;
END;
$$;

Related

Postgres while insert from md5(variable) it inserts column name not column values

below is my postgres procedure
create or replace procedure ds_rs.test_ad () as $$
declare
i integer;
v_command text;
rcd record;
v_count text; v_pk_1 text; v_pk_2 text;
v_account_id varchar(100);
v_query text;
begin
for rcd in ( select t.table_name as object_name, a.table_schema, a.table_name from TLDEPLOY.TABLES_TO_VERIFY t
left join information_schema.tables a on concat
(COALESCE(a.table_schema, ''),'.',COALESCE(a.table_name, '')) = t.table_name order by t.table_name) loop
select count(*), max(column_name), min(column_name) into v_count, v_pk_1, v_pk_2
from information_schema.table_constraints c
join information_schema.columns cl on cl.table_name =c.table_name
where c.constraint_type ='PRIMARY KEY'
and c.table_name =rcd.table_name
and c.TABLE_SCHEMA=rcd.table_schema
and cl.ordinal_position =1
and cl.TABLE_SCHEMA=rcd.table_schema ;
v_command :=('insert into ds_rs.test_table (pk_1,pk_2) select '||v_pk_1||' , '||md5(v_pk_2::text)||' from ds_rs.account');
execute v_command;
end loop;
end; $$
language plpgsql;
while insert into table this query -> md5(v_pk_2::text) -> hash column name and inserts - i want column values to hash and insert
when used as normal - select md5(account_id::text) from account it gives correct value - but when passed as variable it inserts column name not column data

Function for changing a column value in all tables in one schema

I would appreciate it if you could let me know why my code doesn't do anything ? I use PostgreSQL 12.
I want to create a function to change an specific column's value among all tables in a schema.
CREATE OR REPLACE FUNCTION update_cols(_sch text,_col text, _old int, _new int)
RETURNS text AS
$func$
DECLARE
_tbl text;-- table_name
BEGIN
-- Loop over tables
FOR _tbl IN
SELECT quote_ident(table_name)
FROM information_schema.columns
WHERE table_schema = _sch -- name of schema
AND column_name = _col -- name of column
LOOP
RAISE NOTICE '%',
EXECUTE
'UPDATE ' || _tbl || ' SET _col = new_id WHERE _col = old_id';
END LOOP;
RETURN _tbl;
END
$func$ LANGUAGE plpgsql;
-- Call:
SELECT update_cols('','column_name', 10, 13);
It's working now, thanks to the help of #Adrian Klaver's comment.
CREATE OR REPLACE FUNCTION update_cols(_sch text, _old int, _new int)
RETURNS text AS
$func$
DECLARE
_tbl text;-- table_name
BEGIN
-- Loop over tables
FOR _tbl IN
SELECT quote_ident(table_name)
FROM information_schema.columns
WHERE column_name = 'col_name' and TABLE_Schema = _sch
-- name of column
LOOP
EXECUTE format('UPDATE ' ||_tbl|| ' SET col_name = $1 WHERE col_name= $2') USING _new, _old;
END LOOP;
RETURN _tbl;
END
$func$ LANGUAGE plpgsql;

Dynamic query splicing error,a fuction use falie

I want to use the cursor to get the count(data) in all tables under the schema I need.
But I am unfamiliar with SQL, and I still cannot pass the following code:
CREATE OR REPLACE FUNCTION check_tool.get_nae(v_dbName character varying)
RETURNS numeric
LANGUAGE edbspl
SECURITY DEFINER
AS $function$
numInsert numeric;
numCal numeric;
v_result numeric;
query TEXT DEFAULT '';
cursor c_pj is
select t.table_schema::text as tableSchema,
t.table_name::text as tableName
from information_schema.tables t
where t.table_catalog = v_dbName
and t.table_type = 'BASE TABLE'
and t.table_schema in (select schema_name from check_tool.img_schema where dbName = v_dbName);
BEGIN
v_result := -1;
numInsert := 0;
for r_pj in c_pj loop
query := 'select count(*) from '||tableSchema||'.'||tableName||';'; -- select count(*) from "item"."project";
execute query into numCal;
insert into check_tool.img_result(schema_name,table_name,num) values (r_pj.tableSchema,r_pj.tableName,numCal);
numInsert := numInsert + 1;
if numInsert > 1000 then
numInsert := 0;
commit;
end if;
end loop;
commit;
v_result := 0;
RETURN v_result;
EXCEPTION
WHEN others THEN
RETURN v_result;
END get_nae$function$
;
/
I also tried concat() and quote_ident(), but the result is not ideal.
Dynamic SQL should be constructed using format() to better handle identifiers. In Postgres you can't commit inside a function, only in a procedure. Committing in a loop rarely improves the performance to begin with, so I would just skip that. I also wouldn't hide the real error (by just returning -1 or 0) but simply let any exception reach the caller of the procedure. And language edbspl is nothing I know, but in PL/pgSQL I would write it like this:
CREATE OR REPLACE PROCEDURE check_tool.get_nae(v_dbName character varying)
LANGUAGE plpgsql
AS
$body$
declare --<< required in PL/pgSQL to declare variables
numcal numeric;
query TEXT DEFAULT '';
l_rec record;
BEGIN
for l_rec in select t.table_schema::text as tableschema, t.table_name::text as tablename
from information_schema.tables t
where t.table_catalog = v_dbName
and t.table_type = 'BASE TABLE'
and t.table_schema in (select schema_name from check_tool.img_schema where dbName = v_dbName)
loop
query := format('select count(*) from %I.%I', l_rec.tableschema, l_rec.tablename);
execute query into numcal;
insert into check_tool.img_result(schema_name,table_name,num) values (l_rec.tableschema, l_rec.tablename, numcal);
end loop;
commit;
END;
$body$
;
Note that the condition t.table_catalog = v_dbName is actually useless, because you can't query tables that are not in the current database anyway.
Note that you don't really need a stored procedure to do this. You can use query_to_xml() to do this in a single SQL query by adjusting this answer
insert into check_tool.img_result(schema_name,table_name,num)
select table_schema,
table_name,
(xpath('/row/cnt/text()', xml_count))[1]::text::int as row_count
from (
select table_name, table_schema,
query_to_xml(format('select count(*) as cnt from %I.%I', table_schema, table_name), false, true, '') as xml_count
from information_schema.tables
where t.table_type = 'BASE TABLE'
and t.table_schema in (select schema_name from check_tool.img_schema)
) t;

PostgreSQL: compare NULL and normal value

I have a trigger in PostgreSQL
CREATE OR REPLACE FUNCTION table_update_func_pk1() RETURNS trigger AS $$
DECLARE
ri RECORD;
old_value TEXT;
new_value TEXT;
BEGIN
FOR ri IN
SELECT column_name FROM information_schema.columns
WHERE
table_schema = quote_ident('public')
AND table_name = quote_ident(TG_TABLE_NAME)
ORDER BY ordinal_position
LOOP
EXECUTE 'SELECT ($1).' || ri.column_name || '::text' INTO new_value USING NEW;
EXECUTE 'SELECT ($1).' || ri.column_name || '::text' INTO old_value USING OLD;
IF new_value <> old_value AND ri.column_name != 'update_by' THEN
INSERT INTO protokoll(datetime, operation, tabelle, field, pk1, old_value, new_value, update_by)
VALUES(now(), TG_OP, TG_TABLE_NAME, ri.column_name, NEW.cfg, old_value, new_value, NEW.update_by);
END IF;
END LOOP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Sometimes if old_value is changed from NULL to normal value (or from normal value to NULL), the condition "new_value <> old_value" is NOT true but unknown. I would like ask, there is a method that I can get true in the case. Thanks.
Use is distinct from:
if new_value IS DISTINCT FROM old_value and ri.column_name <> 'update_by' then
...
end if;

after update the table insert data like arrays

I have two tables
Table A
col1 col2 col3
Table B
table_name column_name new_value old_value
if any update happened on table A it will insert the data on table B
the output of table B is==>
table_name column_name new_value old_value
---------------- ------------------ -------------- -----------
A {col1}
A {col1,col2} {col1.new_value, {col1.old_value,
col2.new_value} col2.old_value},
so anyone can tell me how to capture the column_names and it store data target table like arrays
Try this
Use Trigger Function
CREATE OR REPLACE FUNCTION update_history()
RETURNS trigger AS
$BODY$
DECLARE col_name VARCHAR[];
DECLARE od_value VARCHAR[];
DECLARE ne_value VARCHAR[];
DECLARE each_column RECORD;
DECLARE each_entity RECORD;
DECLARE column_name VARCHAR;
DECLARE old_value VARCHAR;
DECLARE new_value VARCHAR;
FOR each_column IN
select c.column_name --- Get the all column names in affected table
from information_schema.columns c
where(table_name = tg_relname And c.TABLE_SCHEMA = TG_TABLE_SCHEMA)
LOOP
FOR each_entity IN --- Its used to get old and new columns value
EXECUTE 'SELECT text((' || quote_literal(OLD.*) || '::"' || tg_table_schema || '"."' || tg_relname || '")."' || each_column.column_name || '") as old_val,
text((' || quote_literal(NEW.*) || '::"' || tg_table_schema || '"."' || tg_relname || '")."' || each_column.column_name || '")
AS new_val
FROM "' || tg_table_schema || '"."' || tg_relname || '";'
LOOP
old_value = each_entity.old_val;
new_value = each_entity.new_val;
IF old_value != new_value THEN
i=i+1;
col_name[i]=each_column.column_name;
od_value[i]=old_value;
ne_value[i]=new_value;
END IF;
END LOOP;
END LOOP;
INSERT INTO B
(
tablename,
columnnames,
oldvalues,
newvalues
)
VALUES
(
tg_relname,
col_name,
od_value,
ne_value
);
End if;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
I thinks it's a good case to use hstore extension of PostgreSQL:
create or replace function history_trigger_func()
returns trigger AS
$$
begin
insert into TableB
select
tg_relname,
case when tg_op in ('UPDATE', 'INSERT') then hstore(new) end,
case when tg_op in ('UPDATE', 'DELETE') then hstore(old) end;
return null;
end;
$$
language plpgsql;
create trigger tr_history_trigger after insert or update or delete on TableA
for each row execute procedure history_trigger_func();
sql fiddle demo
You can extend this further by removing columns which are not changing, or, if you're using PostgreSQL 9.3, you can use JSON instead of hstore.