Sql 列安全“插入到t1中选择*自…”?
有什么方法可以插入t1 SELECT*FROM。。。如果列名不一致,它会失败吗 我使用的是Postgresql 9.x,这些列的名称事先不知道 动机:我正在通过非常标准的PL/pgSQL过程定期刷新物化视图:Sql 列安全“插入到t1中选择*自…”?,sql,postgresql,Sql,Postgresql,有什么方法可以插入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
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
我更喜欢先截断,然后选择*插入,而不是拖放/创建,因为它看起来更轻松、更友好。如果有人在视图中添加/删除列,则会失败,然后我会执行删除/创建操作,但这并不重要,在这种情况下,刷新将无法完成,我们很快就会发现问题。重要的是今天发生了什么:有人更改了相同类型视图中两列的顺序,并刷新了插入的虚假数据。您可以查询信息\u 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_属性获取列列表-只需将“从信息_schema.columns中选择”替换为:
将其构建到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;
对于列名列表之间的任何不匹配,完整外部联接将添加一个具有空值的行。因此,如果EXISTS找到一行,则表示某些内容已关闭
如果表或视图不存在或超出范围(不在搜索路径中且不符合模式),则强制转换为::regclass将立即引发异常
如果您还想检查列的数据类型,只需将atttypid添加到USING子句中
顺便说一句:查询pg_目录表通常比查询膨胀的视图int information_模式快一个数量级——information_模式只对SQL标准的遵从性和代码的可移植性有利。由于您正在编写100%特定于Postgres的代码,因此这两种代码在这里都不相关。您不能使用postgresql指定列列表吗?插入t1列1、列2、。。。SELECT*我想他希望它适用于任何表,只要两个表都有相同的列。@njk:列名称事先不知道。列类型如何,这些重要吗?如果它们不匹配,语句可能不会失败,但最终结果可能很差。。。我想我可能会查询信息模式表,以至少验证并获得必要的列名;它不应该增加太多的开销,因为您已经在使用动态SQL了。您不能将名称硬连接到查询中,但它们肯定是已知的,或者可以从v_name.Perfect派生出来。我添加了atttypid以进行类型检查。
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;