检查条件查询表表是否为空

时间:2019-04-05 12:58:46

标签: sql postgresql

我有以下查询,如果相应的表为空,则forelast参数应为false,否则为true

SELECT 'SELECT SETVAL(' ||
       quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) ||
       ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1), ' ||
       CASE    WHEN (SELECT COUNT(*) FROM quote_ident(tablename))=0 THEN FALSE
               ELSE TRUE
           END ||
       ') FROM ' ||
       quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';'
FROM pg_class AS S,
     pg_depend AS D,
     pg_class AS T,
     pg_attribute AS C,
     pg_tables AS PGT
WHERE S.relkind = 'S'
  AND S.oid = D.objid
  AND D.refobjid = T.oid
  AND D.refobjid = C.attrelid
  AND D.refobjsubid = C.attnum
  AND T.relname = PGT.tablename
ORDER BY S.relname;

但是,它总是求值为true。 确实,子查询SELECT COUNT(*) FROM quote_ident(tablename)的结果始终为1:

       quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) ||
       ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1), ' ||
       (SELECT COUNT(*) FROM quote_ident(tablename))||
       ') FROM ' ||
       quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';'
FROM pg_class AS S,
     pg_depend AS D,
     pg_class AS T,
     pg_attribute AS C,
     pg_tables AS PGT
WHERE S.relkind = 'S'
  AND S.oid = D.objid
  AND D.refobjid = T.oid
  AND D.refobjid = C.attrelid
  AND D.refobjsubid = C.attnum
  AND T.relname = PGT.tablename
ORDER BY S.relname;

但是我不知道为什么。

作为一个最小的工作示例,请尝试:

create table empty(id serial, name varchar);
create table notempty(id serial, name varchar);
insert into notempty(name) values('foobar');

现在,当您从上方执行查询时,它将对两个表分别为true进行评估1:

SELECT SETVAL('public.empty_id_seq', COALESCE(MAX(id), -->1<--), 1) FROM public.empty;
SELECT SETVAL('public.notempty_id_seq', COALESCE(MAX(id), 1), 1) FROM public.notempty;

1 个答案:

答案 0 :(得分:1)

最简单的方法是在生成的查询中包含CASE表达式:

SELECT 'SELECT SETVAL(' ||
       quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) ||
       ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1), ' ||
       'CASE    WHEN (SELECT COUNT(*) FROM ' || quote_ident(PGT.schemaname) || '.' || quote_ident(tablename) || ')=0 THEN FALSE
               ELSE TRUE
           END' ||
       ') FROM ' ||
       quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';'
FROM pg_class AS S,
     pg_depend AS D,
     pg_class AS T,
     pg_attribute AS C,
     pg_tables AS PGT
WHERE S.relkind = 'S'
  AND S.oid = D.objid
  AND D.refobjid = T.oid
  AND D.refobjid = C.attrelid
  AND D.refobjsubid = C.attnum
  AND T.relname = PGT.tablename
ORDER BY S.relname;

如果您坚持只使用文字true / false,则需要另一层动态SQL。但是由于表的内容可能会在您生成查询和执行查询之间发生变化,因此无论如何,在查询中包含表达式(即在查询运行时获取结果)都是更安全的选择。

我认为您可以实际上简化此过程,并在函数调用中直接使用count(*) > 0表达式。无需再次子查询同一张表,也不需要CASE表达式,因为该表达式可以简单地包装一个布尔表达式,因为Postgres可以直接使用布尔表达式。

SELECT 'SELECT SETVAL(' ||
       quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) ||
       ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1), COUNT(*) > 0) FROM ' ||
       quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';'
FROM pg_class AS S,
     pg_depend AS D,
     pg_class AS T,
     pg_attribute AS C,
     pg_tables AS PGT
WHERE S.relkind = 'S'
  AND S.oid = D.objid
  AND D.refobjid = T.oid
  AND D.refobjid = C.attrelid
  AND D.refobjsubid = C.attnum
  AND T.relname = PGT.tablename
ORDER BY S.relname;