如何检查表是否包含任何行时传递表名称作为参数?

我试图写一个语句来检查一个表是否包含行:

SELECT COUNT(*) FROM $1 ; 

如果认为我会把表名传入:$ 1

我收到以下错误信息:

在“$ 1”处或附近的语法错误

我的发言有什么错误?

你不能用准备好的陈述来做。 使用function,如柯克build议。 唯一的区别,也许你更安全地select第一行,如:

 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并不直接说你传递的execute准备好的语句的值不能是标识符,但是在任何地方都以标识符不可能的方式提到,例如:

通用计划假定提供给EXECUTE的每个值都是列的不同值之一,并且列值均匀分布。

($ 1是具有或不具有某些属性的列值 。)

基本驱动程序只执行服务器级支持的基本查询格式,而不支持dynamic表名。

这意味着表名需要在你身边转义。 您可以手动执行此操作,也可以依赖支持它的库,如下面使用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 }); 

或者,使用命名参数 :

 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告诉格式化引擎将其作为SQL名称转义。 这个filter也有一个较短的版本~ ,如果你愿意的话,也就是$1~${table~}

此外,我们正在使用方法一 ,因为该查询总是期望返回一行结果。

您可以从系统目录中获取这些信息比查询表本身便宜很多。

 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