Как проверить, содержит ли таблица какие-либо строки при передаче имени таблицы в качестве параметра?

Я пытался написать оператор, чтобы проверить, содержит ли таблица строки:

SELECT COUNT(*) FROM $1 ;

Если бы я понял, что я бы передал имя таблицы в: $1

Я получаю следующее сообщение об ошибке:

синтаксическая ошибка на уровне или около "$1"

Что не так с моим утверждением?


person Rahul Iyer    schedule 02.10.2017    source источник
comment
Какую СУБД вы используете? Требуется динамический sql   -  person Pரதீப்    schedule 02.10.2017
comment
я использую постгрес   -  person Rahul Iyer    schedule 02.10.2017
comment
Проверьте этот вопрос stackoverflow.com/questions/20772195/ и stackoverflow.com/questions/10705616/   -  person Pரதீப்    schedule 02.10.2017
comment
@Pரதீப் Я не понимаю, как это здесь применимо. Почему я не могу просто передать имя таблицы в качестве параметра?   -  person Rahul Iyer    schedule 02.10.2017
comment
Извините, я не знаю, что postgres - парень Sql Server, но в целом идентификаторы не могут передаваться в качестве параметров, которые нам нужны для использования динамического sql.   -  person Pரதீப்    schedule 02.10.2017
comment
Вам нужен динамический SQL.   -  person a_horse_with_no_name    schedule 02.10.2017


Ответы (3)


вы не можете сделать это с подготовленным заявлением. используйте функцию, как предлагает Кирк. Единственная разница, может быть, вам безопаснее выбрать первую строку, например:

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)

документы не говорят напрямую, что значения, которые вы передаете execute подготовлены оператор не может быть идентификатором, но везде они упоминаются таким образом, что идентификатор не может быть, например:

Общий план предполагает, что каждое значение, предоставленное EXECUTE, является одним из отдельных значений столбца и что значения столбца равномерно распределены.

($1 — это значение столбца с некоторыми свойствами или без них.)

person Vao Tsun    schedule 02.10.2017

базовый драйвер выполняет только базовое форматирование запросов, которое поддерживается на уровне сервера, но не поддержка динамических имен таблиц.

Это означает, что имя таблицы должно быть экранировано на вашей стороне. Вы можете сделать это вручную или положиться на библиотеку, которая поддерживает это, как в приведенном ниже примере, который использует pg-обещание:

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    
    });

Фильтр :name указывает механизму форматирования экранировать его как имя SQL. Этот фильтр также имеет более короткую версию ~, если хотите, то есть $1~ или ${table~} соответственно.

Кроме того, мы используем метод one, потому что этот запрос всегда ожидает обратного результата в одну строку.

person vitaly-t    schedule 02.10.2017

Вы можете получить эту информацию из системного каталога намного дешевле и быстрее, чем запрашивать саму таблицу.

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
person Kirk Roybal    schedule 02.10.2017
comment
reltuples — это всего лишь оценка, которая может быть неточной. - person a_horse_with_no_name; 02.10.2017
comment
Верно, но любое число больше 0 доказывает существование. OP не спрашивал, сколько строк в таблице, и оценка вернет как минимум одну страницу строк. - person Kirk Roybal; 09.10.2017
comment
До меня дошло, что означает @a_horse_with_no_name... модифицированный для очень маленьких таблиц. - person Kirk Roybal; 09.10.2017