使用动态查询更新表的“n”列值

Posted

技术标签:

【中文标题】使用动态查询更新表的“n”列值【英文标题】:Updating 'n' column values of table using dynamic query 【发布时间】:2015-04-16 18:54:22 【问题描述】:

我有两个表,thetaconvergence_table,每个都有相同数量的列(这里是 7 列) (w0,w1,...w6; j0,j1,...j6)。我需要将 'w' 值更新为 wn=wn-jn。在这里,我在用户定义的数据类型 wt & jt(%rowtype) 的帮助下更新了 theta 表的值。

select * into jt from convergence_table;                 
select * into wt from theta

update theta                            
    set w0 =  wt.w0-jt.j0, w1 =  wt.w1-jt.j1, w2 =  wt.w2-jt.j2,    
        w3 =  wt.w3-jt.j3, w4 =  wt.w4-jt.j4, w5 =  wt.w5-jt.j5, 
        w6 =  wt.w6-jt.j6;

但是,现在我已经为 thetaconvergence_table 设置了 'n+1' 列数,因此无需编写更新语句并设置所有值w0,w1,w2 .... wn。有没有办法编写一个动态查询来执行从w0wn的所有列值的更新。

我正在尝试以下代码,但它不起作用..

create or replace function sample(c int)
returns void as $$
declare jt convergence_table%rowtype; wt theta%rowtype;  
    query1 text:=''; query2 text:='';

begin

    select * into jt from convergence_table;                
    select * into wt from theta;

    for i in 0..n 
    loop
        query1 := query1 ||'w'||i||' = '||
        'wt.w'||i||' - jt.j'||i||',';
        end loop;

    query2 := trim(trailing ',' from query1);
    query2 := 'update theta set '||query2||';';
    execute query2;

return;
end;
$$ language plpgsql;

这给了我一个错误...

ERROR:  missing FROM-clause entry for table "wt"
LINE 1: update theta set w0 = wt.w0 - jt.j0,w1 = wt.w1 - jt.j1,w2 = ...
                              ^
QUERY:  update theta set w0 = wt.w0 - jt.j0,w1 = wt.w1 - jt.j1,w2 = wt.w2 - jt.j2,w3 = wt.w3 - jt.j3,w4 = wt.w4 - jt.j4,w5 = wt.w5 - jt.j5,w6 = wt.w6 - jt.j6;
CONTEXT:  PL/pgSQL function sample(integer) line 20 at EXECUTE statement

********** Error **********

ERROR: missing FROM-clause entry for table "wt"
SQL state: 42P01
Context: PL/pgSQL function sample(integer) line 20 at EXECUTE statement

有人可以帮忙吗?

【问题讨论】:

基本上,这可以在 plpgsql 中轻松完成。但是,请先澄清任务。你想UPDATE,但是没有定义如何匹配行。你让它看起来每个表中只有一行?在UPDATE 中,通常至少有一列未更改。如果您更改所有列,您还不如DELETE & INSERT - 但您仍然需要定义 what 删除... 是的,theta 和covergence 表只有单行'n'列。 Covergence 表在每次迭代中获取一组随机值,​​因此我必须相应地更新 theta (Wn=W(n-1)-Jn)。这就是场景。即收敛(J),theta(W)最初(null),(5,4,4,3,3,4,4)在第一次迭代之后。 (1,2,3,2,1,4,3) -> (4,2,1,1,2,0,1) 第二次迭代 (2,0,1,2,1,3,2) - > (2,2,0,-1,1,-3,-1) 我最后的 theta 表是 (2,2,0,-1,1,-3,-1)。通常我会有 1000 次迭代。 对不起,我无法附上图片,因为我只是一个初学者。 @ErwinBrandstetter @ErwinBrandstetter,这是我的电子邮件 ID-mouryathelegend@gmail.com。请将您的邮件 ID 发给我,以便我更准确地向您解释问题。谢谢 我很欣赏这个提议,但我宁愿把它留在现场。 Edit 需要澄清的问题。 【参考方案1】:
CREATE OR REPLACE FUNCTION f_upd_dyn(_source regclass, _target regclass)
  RETURNS void AS
$func$
DECLARE
   source_cols text;
   target_cols text;
BEGIN
   SELECT INTO source_cols
          string_agg(quote_ident(attname), ', s.' ORDER BY attname)
   FROM   pg_attribute
   WHERE  attrelid = _source
   AND    NOT attisdropped              -- no dropped (dead) columns
   AND    attnum > 0;                   -- no system columns

   SELECT INTO target_cols
          string_agg(quote_ident(attname), ', ' ORDER BY attname)
   FROM   pg_attribute
   WHERE  attrelid = _target
   AND    NOT attisdropped              -- no dropped (dead) columns
   AND    attnum > 0;                   -- no system columns

   EXECUTE format('UPDATE %s t
                   SET   (%s) = (s.%s)  -- prepend 1st table qual s.
                   FROM  %s s' 
                  -- WHERE t.? = s.?    -- how to join source and target?
                 , _target::text, target_cols
                 , source_cols, _source::text
                 );
END
$func$ LANGUAGE plpgsql;

呼叫:

SELECT f_upd_dyn('convergence_table', 'theta');

生成并执行如下代码:

UPDATE theta t SET (w1, w2, w3) = (s.j1, s.j2, s.j3)
FROM convergence_table s
-- note the missing WHERE condition!

SQL Fiddle.

你最近一直在问一个类似的问题:

Using dynamic query + user defined datatype in Postgres

有更多解释的链接。喜欢这个:

Update multiple columns in a trigger function in plpgsql

【讨论】:

【参考方案2】:

您可以使用 PL/pgsql EXECUTE 命令,从 information_schema.columns 构建您的查询字符串。

【讨论】:

对不起,我是 PostgreSQL 新手,不熟悉,有没有办法修改我上面的代码并得到答案? @Politank-Z ***.com/questions/9643859/… 如果我没记错的话,在这里使用 from 子句将无济于事,wt & jt 是用户定义的类型(行类型)。 & 这确实会给我另一个错误,说 jt & wt 不存在。 @Politank-Z 您可以使用 PL/pgsql 将减法的结果计算到一个数组中,并使用该数组来构造您的更新语句。

以上是关于使用动态查询更新表的“n”列值的主要内容,如果未能解决你的问题,请参考以下文章

带有一个动态列的3个表的mysql查询(i18n)

oracle中一个表的行列转换

在 Oracle 的存储过程中动态运行查询

Oracle 查询中的动态枢轴使用情况

如何在java里实现复杂的动态查询功能?

SQL Unpivot、交叉应用、动态查询?