【发布时间】:2018-05-12 04:01:27
【问题描述】:
通常希望从 SELECT 表达式中插入(例如,使用 WHERE 子句进行限定),但这会使 postgresql 对列类型感到困惑。
例子:
CREATE TABLE example (a uuid primary key, b numeric);
INSERT INTO example
SELECT a, b
FROM (VALUES ('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL)) as data(a,b);
=> ERROR: column "a" is of type uuid but expression is of type text
这可以通过显式转换值来解决:
INSERT INTO example
SELECT a, b
FROM (VALUES ('d853b5a8-d453-11e7-9296-cec278b6b50a'::uuid, NULL::numeric)) as data(a,b);
但这很麻烦,而且是维护负担。有没有办法让 postgres 理解 VALUES 表达式与表行具有相同的类型,即类似于
VALUES('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL)::example%ROWTYPE
编辑:
使用 (data::example).* 的建议很简洁,但不幸的是,当与这样的 WHERE 子句结合使用时,它似乎完全搞砸了 postgres 查询计划器:
INSERT INTO example
SELECT (data::example).*
FROM (VALUES ('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL)) as data
WHERE NOT EXISTS (SELECT * FROM example
WHERE (data::example)
IS NOT DISTINCT FROM example);
对于一张大桌子,这需要几分钟时间。
【问题讨论】:
-
“搞砸刨床”到底是什么意思,我假设您的意思是“性能不佳”。该条件当然不会使用该表上的 any 索引。如果您希望
where条件使用索引,则需要比较索引列,而不是整条记录 -
为什么是“当然”?添加(据我所见)冗余连词
WHERE (data::example).a = a AND (data::example) IS NOT DISTINCT FROM example会导致显着不同的性能行为,这似乎几乎没有声明性。 -
因为您无法创建包含完整记录的索引。索引只能包含列 - 甚至索引中的所有列都不会与具有完整记录的索引相同
-
为什么需要完整记录的索引?两条记录匹配当且仅当所有列都匹配。为什么postgres 不使用
a上的主键在example中查找data.a,然后将匹配的行(如果有)与data::example进行比较?没有其他行可能匹配,所以线性扫描让我感到困惑。 -
因为您将完整的记录与表达式
(data::example) IS NOT DISTINCT FROM example进行比较 - 您不是在比较单个(主键)列。另外:表达式(data::example)不包含有关主键的信息,因为对象type 没有主键。只有一个表有一个主键。
标签: sql postgresql sql-types