Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.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
Arrays 复制具有动态列名的记录_Arrays_Postgresql_Variables_Plpgsql_Dynamic Sql - Fatal编程技术网

Arrays 复制具有动态列名的记录

Arrays 复制具有动态列名的记录,arrays,postgresql,variables,plpgsql,dynamic-sql,Arrays,Postgresql,Variables,Plpgsql,Dynamic Sql,我在PostgreSQL 9.3中有两个不同列的表: CREATE TABLE person1( NAME TEXT NOT NULL, AGE INT NOT NULL ); CREATE TABLE person2( NAME TEXT NOT NULL, AGE INT NOT NULL, ADDRESS CHAR(50), S

我在PostgreSQL 9.3中有两个不同列的表:

CREATE TABLE person1(
   NAME           TEXT    NOT NULL,
   AGE            INT     NOT NULL
);

CREATE TABLE person2(
   NAME           TEXT    NOT NULL,
   AGE            INT     NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL
);

INSERT INTO person2 (Name,    Age, ADDRESS, SALARY)
             VALUES ('Piotr', 20, 'London', 80);
我想将记录从
person2
复制到
person1
,但列名可能会在程序中更改,因此我想在程序中选择联合列名。因此,我创建了一个包含列名交集的数组。接下来我使用一个函数:
insert-into。。。。选择
,但当我按名称将数组变量传递给函数时,会出现错误。像这样:

select column_name into name1 from information_schema.columns where table_name = 'person1';
select column_name into name2 from information_schema.columns where table_name = 'person2';
select * into cols from ( select * from name1 intersect select * from name2) as tmp;
-- Create array with name of columns 
select array (select column_name::text from cols) into cols2;

CREATE OR REPLACE FUNCTION f_insert_these_columns(VARIADIC _cols text[])
  RETURNS void AS
$func$
BEGIN
   EXECUTE (
      SELECT 'INSERT INTO person1 SELECT '
          || string_agg(quote_ident(col), ', ')
          || ' FROM person2'
      FROM   unnest(_cols) col
      );
END
$func$  LANGUAGE plpgsql;


select * from cols2;

  array    
------------
 {name,age}
(1 row)

SELECT f_insert_these_columns(VARIADIC cols2);

这里出了什么问题?

您似乎认为SQL中的
SELECT-INTO
会分配一个变量。但事实并非如此

它创建了一个新的,不鼓励在Postgres中使用它。使用上级
创建表作为
。不仅如此,因为plpgsql内部的
SELECT INTO
的含义不同:

关于SQL变量:

因此,不能像这样调用函数:

SELECT f_insert_these_columns(VARIADIC cols2);
或清洁剂:

SELECT f_insert_these_columns(VARIADIC array)  -- "array" being the unfortunate column name
FROM   cols2
LIMIT  1;
关于short
语法:

更好的解决方案 要在两个表之间复制列名称相同的所有行,请执行以下操作:

CREATE OR REPLACE FUNCTION f_copy_rows_with_shared_cols(
    IN  _tbl1 regclass
  , IN  _tbl2 regclass
  , OUT rows int
  , OUT columns text)
  LANGUAGE plpgsql AS
$func$
BEGIN
   SELECT INTO columns         -- proper use of SELECT INTO!
          string_agg(quote_ident(attname), ', ')
   FROM  (
      SELECT attname
      FROM   pg_attribute
      WHERE  attrelid IN (_tbl1, _tbl2)
      AND    NOT attisdropped  -- no dropped (dead) columns
      AND    attnum > 0        -- no system columns
      GROUP  BY 1
      HAVING count(*) = 2
      ) sub;

   EXECUTE format('INSERT INTO %1$s(%2$s) SELECT %2$s FROM %3$s'
                  , _tbl1, columns, _tbl2);

   GET DIAGNOSTICS rows = ROW_COUNT;  -- return number of rows copied
END
$func$;
电话:

结果:

rows | columns
-----+---------
3    | name, age
要点
  • 注意在plpgsql中正确使用
    SELECT INTO
    进行赋值

  • 注意数据类型
    regclass
    的使用。这允许使用模式限定表名(可选),并防止SQL注入尝试:

  • 关于获取诊断信息:

  • 关于
    OUT
    参数:


它可以工作:选择f_insert_这些列(可变(表列2限制1));Thx用于help@PiotrOlkiewicz我考虑了另一种解决方案,你的功能很完美。此外,我不需要创建临时对象。这是一个很好的解决方案。谢谢你的帮助
CREATE OR REPLACE FUNCTION f_copy_rows_with_shared_cols(
    IN  _tbl1 regclass
  , IN  _tbl2 regclass
  , OUT rows int
  , OUT columns text)
  LANGUAGE plpgsql AS
$func$
BEGIN
   SELECT INTO columns         -- proper use of SELECT INTO!
          string_agg(quote_ident(attname), ', ')
   FROM  (
      SELECT attname
      FROM   pg_attribute
      WHERE  attrelid IN (_tbl1, _tbl2)
      AND    NOT attisdropped  -- no dropped (dead) columns
      AND    attnum > 0        -- no system columns
      GROUP  BY 1
      HAVING count(*) = 2
      ) sub;

   EXECUTE format('INSERT INTO %1$s(%2$s) SELECT %2$s FROM %3$s'
                  , _tbl1, columns, _tbl2);

   GET DIAGNOSTICS rows = ROW_COUNT;  -- return number of rows copied
END
$func$;
SELECT * FROM f_copy_rows_with_shared_cols('public.person2', 'public.person1');
rows | columns
-----+---------
3    | name, age