4

我正在尝试编写一个查询来判断表中命名的列s是否a.t具有其默认值(这是一个非常大的 base64 字符串)。所以我尝试了:

SELECT 1 FROM a.t WHERE s = (
   SELECT column_default FROM information_schema.columns
   WHERE (table_schema, table_name, column_name) = ('a', 't', 's'))
   AND uname = 'joe';

哪个不起作用,所以我注意到结果中information_schema.columns有一些常规查询没有的东西:

SELECT column_default FROM information_schema.columns
WHERE (table_schema, table_name, column_name) = ('a', 't', 's');

column_default | 'data:image/png;base64,iVBO...QmCC'::text

比。

SELECT s FROM a.t WHERE uname = 'joe';

s | data:image/png;base64,iVBO...QmCC

请注意缺少引号和明确的演员表。
这就是不匹配的原因吗?列s定义为 type text
如何更改查询,以便测试列值与其默认值之间的相等性?

4

1 回答 1

2

您从信息模式(或我的解决方案中的系统目录)中检索到的只是表示表达式的字符串文字。您需要实际执行它以获取value它可以像您的情况或任何其他表达式一样是微不足道的。这就是您需要动态 SQL的地方。(或者从第一个查询的结果中连接客户端中的第二个查询。)

此相关答案中的详细说明:
Generate DEFAULT values in a CTE UPSERT using PostgreSQL 9.3
(您还可以在此处找到没有动态 SQL 的替代路线的说明。)

这个DO声明可以解决问题。

DO
$do$
DECLARE
   _data text := 'data:image/png;base64,iVBO...QmCC';
   _answer bool;
BEGIN

EXECUTE (
   SELECT format('SELECT %s = $1', d.adsrc)
   FROM   pg_attribute a 
   JOIN   pg_attrdef   d ON (d.adrelid, d.adnum) = (a.attrelid, a.attnum)
   WHERE  a.attrelid = 'a.t'::regclass   -- schema.table
   AND    a.attname = 's'
   )
USING  _data
INTO   _answer;

RAISE NOTICE '%', answer;

END
$do$;

对于重复使用,我会将其包装到 plpgsql 函数中。有很多相关的答案。

另请注意,列默认值可能会产生副作用,例如增加序列。不是在这种特殊情况下,但通常我建议在执行之前检查默认值。

于 2014-06-02T18:00:06.417 回答