有没有办法做INSERT INTO t1 SELECT * FROM...
,如果列名不一致就会失败?
我正在使用Postgresql 9.x事先不知道列名。
动机:我正在通过(非常标准的)PL / pgSQL程序定期刷新物化视图:
CREATE OR REPLACE FUNCTION matview_refresh(name) RETURNS void AS
$BODY$
DECLARE
matview ALIAS FOR $1;
entry matviews%ROWTYPE;
BEGIN
SELECT * INTO entry FROM matviews WHERE mv_name = matview;
IF NOT FOUND THEN
RAISE EXCEPTION 'Materialized view % does not exist.', matview;
END IF;
EXECUTE 'TRUNCATE TABLE ' || matview;
EXECUTE 'INSERT INTO ' || matview || ' SELECT * FROM ' || entry.v_name;
UPDATE matviews SET last_refresh=CURRENT_TIMESTAMP WHERE mv_name=matview;
RETURN;
END
我更喜欢TRUNCATE
后跟SELECT * INTO
而不是DROP / CREATE,因为它看起来更轻,并且更友好。如果有人在视图中添加/删除列(然后我会执行DROP / CREATE),它会失败,但是,无关紧要,在这种情况下,刷新将无法完成,我们很快就会发现问题。重要的是今天发生的事情:有人改变了视图的两列(相同类型)的顺序,并刷新了插入的虚假数据。
答案 0 :(得分:1)
您可以查询information_schema.columns以按正确的顺序获取列:
SELECT INTO cols array_to_string(array_agg(column_name::text), ',')
FROM (
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'matview'
ORDER BY ordinal_position
) AS x;
EXECUTE 'INSERT INTO ' || matview || ' SELECT ' || cols || ' FROM ' || entry.v_name;
您可以直接从pg_attribute获取列列表 - 只需从SELECT
替换内部information_schema.columns
:
SELECT attname AS column_name
FROM pg_attribute
WHERE attrelid = 'matview'::regclass AND attisdropped = false
ORDER BY attnum;
答案 1 :(得分:1)
将此构建到plpgsql函数中以验证视图和表是否完全共享相同序列中的相同列名:
IF EXISTS (
SELECT 1
FROM (
SELECT *
FROM pg_attribute
WHERE attrelid = matview::regclass
AND attisdropped = FALSE
AND attnum > 0
) t
FULL OUTER JOIN (
SELECT *
FROM pg_attribute
WHERE attrelid = entry.v_name::regclass
AND attisdropped = FALSE
AND attnum > 0
) v USING (attnum, attname) -- atttypid to check for type, too
WHERE t.attname IS NULL
OR v.attname IS NULL
) THEN
RAISE EXCEPTION 'Mismatch between table and view!';
END IF;
对于列名列表之间的任何不匹配,FULL OUTER JOIN
会为NULL
值添加一行。因此,如果EXISTS
找到一行,则表示某些内容已关闭。
如果表或视图不存在(或者超出范围 - 不在::regclass
且没有模式限定),则转换为search_path
会立即引发异常。
如果您还想检查列的数据类型,只需将atttypid
添加到USING
子句中。
顺便说一句:查询pg_catalog
表通常比查询膨胀的视图int information_schema
快一个数量级 - information_schema仅适用于SQL标准兼容性和代码的可移植性。由于您正在编写100%Postgres特定代码,因此这两者都不相关。