PostgreSQL check if table exist throwing "relation does not exist" error - postgresql

In PostgreSQL I try to check if table exist:
SELECT EXISTS (SELECT * FROM table_name);
And it throwing an error. How can I check if table already exists so the result will be boolean? Because currently I can achieve the same with try-catch (enters to catch if not exist) instead of if-else on the result...
Thanks,

Either of these should work, though depending on how your permissions are set up you may not have access to the tables:
SELECT EXISTS (SELECT relname FROM pg_class WHERE relname = 'table_name');
SELECT EXISTS (SELECT table_name FROM information_schema.tables WHERE table_name = 'table_name');

Related

truncate all tables in Postgres except for the ones provided in a list

I want to truncate the whole database while maintaining the sequence identity. I came up with something like this:
WITH tables_to_be_truncated AS (
SELECT table_name
FROM information_schema.tables
WHERE table_type='BASE TABLE'
AND table_schema='public'
AND table_name NOT IN ('admins', 'admin_roles')
)
TRUNCATE TABLE (SELECT table_name FROM tables_to_be_truncated) CONTINUE IDENTITY RESTRICT;
I get this error:
ERROR: syntax error at or near "TRUNCATE"
LINE 9: TRUNCATE TABLE (SELECT table_name FROM tables_to_be_truncated...
I do have the permissions to truncate the tables and when I run for a single table like TRUNCATE TABLE access_tokens it works fine.
I also tried with this
TRUNCATE TABLE (SELECT string_agg(table_name, ', ') FROM tables_to_be_truncated) CONTINUE IDENTITY RESTRICT
which didn't work as well.
From what I see in other posts, people are doing it with functions. I didn't want to go down this path honestly but if this is the only way...
You don't need a function for that. An anonymous code block will do:
DO $$
DECLARE row RECORD;
BEGIN
FOR row IN SELECT table_name
FROM information_schema.tables
WHERE table_type='BASE TABLE'
AND table_schema='public'
AND table_name NOT IN ('admins', 'admin_roles')
LOOP
EXECUTE format('TRUNCATE TABLE %I CONTINUE IDENTITY RESTRICT;',row.table_name);
END LOOP;
END;
$$;
Other than that I don't think you'll be able to run dynamic queries with pure SQL.
Demo: db<>fiddle

Postgres 12.4 gives function does not exists error

I am running the below query in postgres 12.4 :
SELECT (TABLE_SCHEMA || '"."' || TABLE_NAME) as table_name,
pg_size_pretty(pg_table_size(table_name)) as table_size,
pg_size_pretty(pg_indexes_size(table_name)) AS indexes_size,
pg_size_pretty(pg_total_relation_size(table_name)) as total_size
from information_schema.TABLES nowait
where TABLE_SCHEMA='myschema'
order by pg_total_relation_size(table_name) desc;
I am getting the below error message :
ERROR: function pg_table_size(information_schema.sql_identifier) does not exist
LINE 1: ..."."' || TABLE_NAME) as table_name, pg_size_pretty(pg_table_s...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Can anyone tell me what exactly am I missing here? I would also like to mention that the exact same query runs fine in postgres version 9.5. I couldn't find anything in the postgres 12.4 documentation as well. Any thoughts/suggestions are welcomed. Thanks!
Per this thread on the Postgres --general list:
SELECT
pg_size_pretty(pg_table_size(quote_ident(table_name))),
pg_size_pretty(pg_indexes_size(quote_ident(table_name))) AS indexes_size,
pg_size_pretty(pg_total_relation_size(quote_ident(table_name))) AS total_size
FROM
information_schema.tables
WHERE
table_schema = 'myschema'
;
Your previous query was never working with this:
(TABLE_SCHEMA || '"."' || TABLE_NAME) as table_name
it was just using the value in the table_name column which previously was a varchar so it worked in pg_table_size(). Now that the column type has changed you need to use quote_ident() to correctly cast it. FYI, the above will work in 9.5 also.

Phantom Postgres table exists but can't be dropped?

I seem to have some sort of phantom table in Postgres.
Suppose I do the following:
select * from information_schema.tables where table_schema = 'public';
I get:
table_name | table_type | ...
phantom_table BASE TABLE
...
So, I run:
drop table phantom_table cascade;
And I get:
ERROR: table "phantom_table" does not exist
Things I've tried:
Checking for spelling errors and making sure the schema is correct (I've even copied/pasted table name out of information schema query results).
vacuum
Reconnecting.
Killing other running processes from my user (nobody else is using the DB).
Checking for active locks on the table (there aren't any).
Anybody have any other ideas for things I should try?
You probably have some white space at the end of the name.
The easiest way is to let the format() function generate you the correct table name and statement:
select format('drop table %I.%I;', table_schema, table_name) as drop_statement
from information_schema.tables
where table_schema = 'public'
and table_name like '%phantom%';
Edit: it seems that psql on Windows isn't able to handle an identifier with a new line in a drop statement (it does when creating the table however).
To workaround that, you can use a DO block:
do
$$
declare
l_stmt text;
begin
select format('drop table %I.%I;', table_schema, table_name) as drop_statement
into l_stmt
from information_schema.tables
where table_schema = 'public'
and table_name like '%phantom%';
execute l_stmt;
end;
$$
;
Note this code assumes that only a single table with that name exists.

postgres select all tables in the current search path?

I need to find all the visible tables in my current schema search path. I tried:
SELECT *
FROM pg_tables
AND schemaname IN (SHOW search_path)
but it errors with:
PGError: ERROR: syntax error at or near "search_path"
LINE 3: AND schemaname IN (SHOW search_path)
The pg_*_is_visible() set of functions is provided for this purpose. Here is one way to use them:
SELECT * FROM pg_class WHERE relkind IN ('r', 'v') AND pg_table_is_visible(oid);
You can get the current schemas using CURRENT_SCHEMAS() function. It will resolve any references in the search path for you (e.g. $user)
SELECT * FROM pg_tables WHERE schemaname = ANY (CURRENT_SCHEMAS(false));
You could also use the more standard information_schema pseudo-schema.
SELECT * FROM information_schema.tables WHERE table_schema = ANY (CURRENT_SCHEMAS(false));

Where is temporary table created?

Where can I find created temporary table in posgresql folders? If I do select * from temp_table; then I got result, but cannot see it structure of my database in the PgAdmin?
Temporary tables get put into a schema called "pg_temp_NNN", where "NNN" indicates which server backend you're connected to. This is implicitly added to your search path in the session that creates them.
Note that you can't access one connection's temp tables via another connection... so depending on how exactly pgAdmin organises its connections, even being able to find the tables in the object explorer might not be useful.
Here is one way to get the name of the pg_temp_nnn schema for your session:
select distinct 'pg_temp_'||sess_id from pg_stat_activity where procpid = pg_backend_pid()
This will identify the session that is running that SQL statement itself, and returns the session id that it is running under.
You can then use this to list all your temporary tables:
select *
from information_schema.tables
where table_schema =
( select distinct 'pg_temp_'||sess_id
from pg_stat_activity
where procpid = pg_backend_pid()
)
Or to get the table structure:
select *
from information_schema.columns
where table_schema =
( select distinct 'pg_temp_'||sess_id
from pg_stat_activity
where procpid = pg_backend_pid()
)
and table_name = 'my_temp_table'
order by ordinal_position