I was trying to write a statement to check if an table contains rows:
SELECT COUNT(*) FROM $1 ;
If figured I would pass in the table name into: $1
I get the following error message:
syntax error at or near "$1"
What is wrong with my statement ?
I was trying to write a statement to check if an table contains rows:
SELECT COUNT(*) FROM $1 ;
If figured I would pass in the table name into: $1
I get the following error message:
syntax error at or near "$1"
What is wrong with my statement ?
You can get this information from the system catalog a lot cheaper and faster than querying the table itself.
CREATE OR REPLACE FUNCTION table_empty(tablename text, tableschema text)
RETURNS BOOLEAN AS $$
BEGIN
RETURN (SELECT CASE WHEN (reltuples::integer > 0)
THEN false
ELSE (SELECT count(*) = 0
FROM quote_ident(tableschema || '.' || tablename) )
END
FROM pg_namespace nc
JOIN pg_class c
ON nc.oid = c.relnamespace
WHERE relname=tablename AND nc.nspname = tableschema);
END;
$$
LANGUAGE plpgsql;
SELECT table_empty('pg_class','pg_catalog');
table_empty
-----------
f
1 row
The base driver does only the basic query formatting that's supported on the server level, which doesn't support dynamic table names.
This means the table name needs to be escaped on your side. You can either do this manually, or you can rely on a library that supports it, like the example below that uses pg-promise:
db.one('SELECT count(*) FROM $1:name', table, a => +a.count)
.then(count => {
// count = the integer record count
})
.catch(error => {
// either table doesn't exist, or a connectivity issue
});
Or, by using Named Parameters:
db.one('SELECT count(*) FROM ${table:name}', {table}, a => +a.count)
.then(count => {
// count = the integer record count
})
.catch(error => {
// either table doesn't exist, or a connectivity issue
});
Filter :name tells the formatting engine to escape it as an SQL Name. This filter also has a shorter version ~, if you prefer, i.e. $1~ or ${table~} accordingly.
Also, we are using method one, because that query always expects one-row result back.
you can't do it with prepared statement. use function as Kirk suggests. The only difference, maybe you are safer to select first row, like :
t=# create or replace function tempty(tn text) returns boolean as
$$
declare
c int;
begin
execute format('select 1 from %I limit 1',tn) into c;
return NOT coalesce(c,0) > 0;
end;
$$ language plpgsql
;
CREATE FUNCTION
t=# create table empty(i int);
CREATE TABLE
t=# select tempty('empty');
tempty
--------
t
(1 row)
t=# select tempty('pg_class');
tempty
--------
f
(1 row)
docs do not say directly that values you pass to execute prepared statement can't be identifiers, yet everywhere they are mentionned in a way that identifier could not be, eg:
A generic plan assumes that each value supplied to EXECUTE is one of the column's distinct values and that column values are uniformly distributed.
($1 is a column value with or without some properties.)