简体   繁体   中英

how to reference a schema variable in plpgsql

I am trying to learn plpgsql code to automate some data cleaning in a database.

My current task is to replace all of '999' values in numeric fields with 'NaN'. What I am trying to do is: 1) find all columns in a schema that are numeric 2) loop through these and use 'update/replace'

My code is below. I think my main problem is finding out how to reference the schema.table in the update statement (but I am sure there are other things I have not done too well).

The error that I am getting is that the relation is not recognised. Any assistance would be appreciated

Becky

CREATE OR REPLACE FUNCTION household.nodata_replace(schemanm text)
RETURNS VOID as $$
DECLARE
  cname text;
  tname text;
BEGIN
   --FOR col IN
  for cname,tname in SELECT column_name::text,table_name::text FROM information_schema.columns
     where table_schema = schemanm and data_type in ('integer','double precision')

     LOOP

     RAISE NOTICE 'cname is: % from %', cname, tname;
     EXECUTE 'update '||schemanm::regclass||'.' ||tname::regclass||
 ' set ' || quote_ident(cname) ||' = replace('  || quote_ident(cname) ||', 999, NaN);';
     END LOOP;


END;
$$
LANGUAGE plpgsql;

I would rather use format() for this. The placeholder %I takes care of properly quoting identifiers if needed.

replace() is for string manipulation not for replacing numbers. To assign the value NaN use set xxx = 'NaN' but you cannot do this for an integer value. Integers do not support NaN

So your dynamic SQL boils down to:

execute format('update %I.%I set %I = ''NaN'' where %I = 999, schemanm, tname, cname, cname);

But you will need to change your where clause to not include integer columns. You probably want to include numeric and real as well:

and data_type in ('numeric','double precision', 'real')

If you just want to mark the "absence of information", I would rather store null in those columns. In that case you don't need to distinguish between the different data types:

execute format('update %I.%I set %I = null where %I = 999, schemanm, tname, cname, cname);

try to rework your query like following:

EXECUTE 'update '|| (schemanm||'.'||tname)::regclass ||' set ' || quote_ident(cname) ||' = ''NaN'' WHERE '|| quote_ident(cname) ||' = 999;'

because casting to regclass is trying to search within registered relations. and schema is not relation.

or you can

EXECUTE 'update '|| quote_ident(schemanm)||'.'||quote_ident(tname) ||' set ' || quote_ident(cname) ||' = ''NaN'' WHERE '|| quote_ident(cname) ||' = 999;'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM