Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 列安全“插入到t1中选择*自…”?_Sql_Postgresql - Fatal编程技术网

Sql 列安全“插入到t1中选择*自…”?

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

有什么方法可以插入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

我更喜欢先截断,然后选择*插入,而不是拖放/创建,因为它看起来更轻松、更友好。如果有人在视图中添加/删除列,则会失败,然后我会执行删除/创建操作,但这并不重要,在这种情况下,刷新将无法完成,我们很快就会发现问题。重要的是今天发生了什么:有人更改了相同类型视图中两列的顺序,并刷新了插入的虚假数据。

您可以查询信息\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;