【问题标题】:How to check if a table contains any rows when passing the table name as a parameter?将表名作为参数传递时如何检查表是否包含任何行?
【发布时间】:2018-03-13 05:05:35
【问题描述】:

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

SELECT COUNT(*) FROM $1 ;

如果我想我会将表名传入:$1

我收到以下错误消息:

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

我的陈述有什么问题?

【问题讨论】:

  • 您使用的是哪个 DBMS?它需要动态sql
  • 我正在使用 postgres
  • @Pரதீப் 我不明白这如何适用于此。为什么我不能只传入表名作为参数?
  • 对不起,我不知道 postgres 是一个 Sql Server 人,但一般标识符不能作为参数传递,我们需要使用动态 sql。

标签: sql node.js postgresql node-postgres


【解决方案1】:

你不能用准备好的语句来做到这一点。使用柯克建议的功能。唯一的区别,也许你选择第一行更安全,比如:

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 直接表示您传递给execute 准备好的语句的值不能是标识符,但是在任何地方都以标识符不可能的方式提及它们,例如:

通用计划假定提供给 EXECUTE 的每个值都是 该列的不同值并且该列值是一致的 分布式。

($1 是一个列值,有或没有某些属性。)

【讨论】:

    【解决方案2】:

    base driver 仅执行服务器级别支持的基本查询格式,不支持动态表名。

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

    或者,使用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 告诉格式化引擎将其转义为 SQL 名称。此过滤器还有一个较短的版本~,如果您愿意,也可以相应地使用$1~${table~}

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

    【讨论】:

      【解决方案3】:

      您可以从系统目录中获取这些信息,比查询表本身更便宜、更快捷。

      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
      

      【讨论】:

      • reltuples 只是一个估计,它可能并不准确。
      • 是的,但任何大于 0 的数字都证明存在。 OP 没有询问表中有多少行,并且估计将返回至少一页的行。
      • 让我明白了@a_horse_with_no_name 的意思...针对非常小的桌子进行了修改。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-05
      • 2021-01-15
      • 2023-03-06
      • 2012-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多