Nie pamiętam, kiedy ostatnio musiałem użyć wyraźnego kursora do zapętlenia w plpgsql.
Użyj niejawnego kursora FOR
pętla, to znacznie czystsze:
DO
$$
DECLARE
rec record;
nbrow bigint;
BEGIN
FOR rec IN
SELECT *
FROM pg_tables
WHERE tablename NOT LIKE 'pg\_%'
ORDER BY tablename
LOOP
EXECUTE 'SELECT count(*) FROM '
|| quote_ident(rec.schemaname) || '.'
|| quote_ident(rec.tablename)
INTO nbrow;
-- Do something with nbrow
END LOOP;
END
$$;
Musisz podać nazwę schematu, aby to działało dla wszystkich schematów (w tym tych, których nie ma w Twojej search_path
).
Poza tym faktycznie potrzebujesz używać quote_ident()
lub format()
z %I
lub regclass
zmienna zabezpieczająca przed wstrzyknięciem SQL. Nazwa tabeli może być prawie dowolna wewnątrz podwójnych cudzysłowów. Zobacz:
- Nazwa tabeli jako parametr funkcji PostgreSQL
Drobny szczegół:pomiń podkreślenie (_
) w LIKE
wzór, aby uczynić go dosłownym podkreślenie:tablename NOT LIKE 'pg\_%'
Jak mogę to zrobić:
DO
$$
DECLARE
tbl regclass;
nbrow bigint;
BEGIN
FOR tbl IN
SELECT c.oid
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND n.nspname NOT LIKE 'pg\_%' -- system schema(s)
AND n.nspname <> 'information_schema' -- information schema
ORDER BY n.nspname, c.relname
LOOP
EXECUTE 'SELECT count(*) FROM ' || tbl INTO nbrow;
-- raise notice '%: % rows', tbl, nbrow;
END LOOP;
END
$$;
Zapytanie pg_catalog.pg_class
zamiast tablename
, dostarcza OID tabeli.
Typ identyfikatora obiektu regclass
przydaje się do uproszczenia. W szczególności nazwy tabel są w podwójnych cudzysłowach i automatycznie kwalifikowane według schematu (także zapobiegają wstrzykiwaniu SQL).
To zapytanie wyklucza również tabele tymczasowe (schemat tymczasowy nosi nazwę pg_temp%
wewnętrznie).
Aby uwzględnić tylko tabele z danego schematu:
AND n.nspname = 'public' -- schema name here, case-sensitive