在 Postgres 中使用动态查询 + 用户定义的数据类型
Using dynamic query + user defined datatype in Postgres
我需要一个函数来标准化我的输入 table features
值。
我的 features
table 有 9 列,其中 x1,x2...x6
是我需要缩放的输入列。
我可以使用静态查询来完成:
create or replace function scale_function()
returns void as $$
declare tav1 features%rowtype; rang1 features%rowtype;
begin
select avg(n),avg(x0),avg(x1),avg(x2),avg(x3),avg(x4),avg(x5),avg(x6),avg(y)
into tav1 from features;
select max(n)-min(n),max(x0)-min(x0),max(x1)-min(x1),max(x2)-min(x2),max(x3)-min(x3),
max(x4)-min(x4),max(x5)-min(x5),max(x6)-min(x6),max(y)-min(y)
into rang1 from features;
update features
set x1= (x1-tav1.x1)/(rang1.x1),x2= (x2-tav1.x2)/(rang1.x2),
x3= (x3-tav1.x3)/(rang1.x3),x4= (x4-tav1.x4)/(rang1.x4),
x5= (x5-tav1.x5)/(rang1.x5),x6= (x6-tav1.x6)/(rang1.x6),
y= (y-tav1.y)/(rang1.y);
return;
end;
$$ language plpgsql;
但现在我需要一个动态查询来缩放 n 列值,即 x1,x2...,xn
(假设我有 200 多列)在我的 features
table。我正在尝试这段代码,但这行不通,因为用户定义的数据类型存在问题:
create or replace function scale_function(n int)
returns void as $$
declare
tav1 features%rowtype;
rang1 features%rowtype;
query1 text :=''; query2 text :='';
begin
for i in 0..n
loop
query1 := query1 ||',avg(x'||i||')';
query2 := query2||',max(x'||i||')-min(x'||i||')';
end loop;
query1 := 'select avg(n)'||query1||',avg(y) into tav1 from features;';
execute query1;
query2 := 'select max(n)-min(n)'||query2||',max(y)-min(y) into rang1 from features;';
execute query2;
update features
set x1= (x1-tav1.x1)/(rang1.x1), ... ,xn=(xn-tav1.xn)/(rang1.xn)
,y= (y-tav1.y)/(rang1.y);
return;
end;
$$ language plpgsql;
在这里,我试图将列的 avg()
值放入用户定义的行类型 tav1
中,并且必须使用该 tav1
值进行更新。
任何人都可以帮助我如何使用 'n' 此类列的动态查询来更新 features
table 值吗?
************ Error ************
ERROR: column "avg" specified more than once
SQL state: 42701
Context: SQL statement "select avg(n),avg(x0),avg(x1),avg(x2),avg(x3),avg(x4),avg(x5),avg(x6),avg(y) into tav1 from features;"
PL/pgSQL function scale_function(integer) line 12 at EXECUTE statement
我正在使用 PostgreSQL 9.3.0。
基本UPDATE
用这个更短、更高效的单个 UPDATE
命令替换第一个查询:
UPDATE features
SET (x1,x2,x3,x4,x5,x6, y)
= ((x1 - g.avg1) / g.range1
, (x2 - g.avg2) / g.range2
-- , (x3 - ...
, (y - g.avgy) / g.rangey)
FROM (
SELECT avg(x1) AS avg1, max(x1) - min(x1) AS range1
, avg(x2) AS avg2, max(x2) - min(x2) AS range2
-- , avg(x3) ...
, avg(y) AS avgy, max(y) - min(y) AS rangey
FROM features
) g;
关于短 UPDATE
语法:
- SQL update fields of one table from fields of another one
动态函数
建立在更简单的查询之上,这是一个用于任意数量列的动态函数:
CREATE OR REPLACE FUNCTION scale_function_dyn()
RETURNS void AS
$func$
DECLARE
cols text; -- list of target columns
vals text; -- list of values to insert
aggs text; -- column list for aggregate query
BEGIN
SELECT INTO cols, vals, aggs
string_agg(quote_ident(attname), ', ')
, string_agg(format('(%I - g.%I) / g.%I'
, attname, 'avg_' || attname, 'range_' || attname), ', ')
, string_agg(format('avg(%1$I) AS %2$I, max(%1$I) - min(%1$I) AS %3$I'
, attname, 'avg_' || attname, 'range_' || attname), ', ')
FROM pg_attribute
WHERE attrelid = 'features'::regclass
AND attname NOT IN ('n', 'x0') -- exclude columns from update
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0; -- no system columns
EXECUTE format('UPDATE features
SET (%s) = (%s)
FROM (SELECT %s FROM features) g'
, cols, vals, aggs);
END
$func$ LANGUAGE plpgsql;
更多解释的相关答案:
- Update multiple columns in a trigger function in plpgsql
我需要一个函数来标准化我的输入 table features
值。
我的 features
table 有 9 列,其中 x1,x2...x6
是我需要缩放的输入列。
我可以使用静态查询来完成:
create or replace function scale_function()
returns void as $$
declare tav1 features%rowtype; rang1 features%rowtype;
begin
select avg(n),avg(x0),avg(x1),avg(x2),avg(x3),avg(x4),avg(x5),avg(x6),avg(y)
into tav1 from features;
select max(n)-min(n),max(x0)-min(x0),max(x1)-min(x1),max(x2)-min(x2),max(x3)-min(x3),
max(x4)-min(x4),max(x5)-min(x5),max(x6)-min(x6),max(y)-min(y)
into rang1 from features;
update features
set x1= (x1-tav1.x1)/(rang1.x1),x2= (x2-tav1.x2)/(rang1.x2),
x3= (x3-tav1.x3)/(rang1.x3),x4= (x4-tav1.x4)/(rang1.x4),
x5= (x5-tav1.x5)/(rang1.x5),x6= (x6-tav1.x6)/(rang1.x6),
y= (y-tav1.y)/(rang1.y);
return;
end;
$$ language plpgsql;
但现在我需要一个动态查询来缩放 n 列值,即 x1,x2...,xn
(假设我有 200 多列)在我的 features
table。我正在尝试这段代码,但这行不通,因为用户定义的数据类型存在问题:
create or replace function scale_function(n int)
returns void as $$
declare
tav1 features%rowtype;
rang1 features%rowtype;
query1 text :=''; query2 text :='';
begin
for i in 0..n
loop
query1 := query1 ||',avg(x'||i||')';
query2 := query2||',max(x'||i||')-min(x'||i||')';
end loop;
query1 := 'select avg(n)'||query1||',avg(y) into tav1 from features;';
execute query1;
query2 := 'select max(n)-min(n)'||query2||',max(y)-min(y) into rang1 from features;';
execute query2;
update features
set x1= (x1-tav1.x1)/(rang1.x1), ... ,xn=(xn-tav1.xn)/(rang1.xn)
,y= (y-tav1.y)/(rang1.y);
return;
end;
$$ language plpgsql;
在这里,我试图将列的 avg()
值放入用户定义的行类型 tav1
中,并且必须使用该 tav1
值进行更新。
任何人都可以帮助我如何使用 'n' 此类列的动态查询来更新 features
table 值吗?
************ Error ************ ERROR: column "avg" specified more than once SQL state: 42701 Context: SQL statement "select avg(n),avg(x0),avg(x1),avg(x2),avg(x3),avg(x4),avg(x5),avg(x6),avg(y) into tav1 from features;" PL/pgSQL function scale_function(integer) line 12 at EXECUTE statement
我正在使用 PostgreSQL 9.3.0。
基本UPDATE
用这个更短、更高效的单个 UPDATE
命令替换第一个查询:
UPDATE features
SET (x1,x2,x3,x4,x5,x6, y)
= ((x1 - g.avg1) / g.range1
, (x2 - g.avg2) / g.range2
-- , (x3 - ...
, (y - g.avgy) / g.rangey)
FROM (
SELECT avg(x1) AS avg1, max(x1) - min(x1) AS range1
, avg(x2) AS avg2, max(x2) - min(x2) AS range2
-- , avg(x3) ...
, avg(y) AS avgy, max(y) - min(y) AS rangey
FROM features
) g;
关于短 UPDATE
语法:
- SQL update fields of one table from fields of another one
动态函数
建立在更简单的查询之上,这是一个用于任意数量列的动态函数:
CREATE OR REPLACE FUNCTION scale_function_dyn()
RETURNS void AS
$func$
DECLARE
cols text; -- list of target columns
vals text; -- list of values to insert
aggs text; -- column list for aggregate query
BEGIN
SELECT INTO cols, vals, aggs
string_agg(quote_ident(attname), ', ')
, string_agg(format('(%I - g.%I) / g.%I'
, attname, 'avg_' || attname, 'range_' || attname), ', ')
, string_agg(format('avg(%1$I) AS %2$I, max(%1$I) - min(%1$I) AS %3$I'
, attname, 'avg_' || attname, 'range_' || attname), ', ')
FROM pg_attribute
WHERE attrelid = 'features'::regclass
AND attname NOT IN ('n', 'x0') -- exclude columns from update
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0; -- no system columns
EXECUTE format('UPDATE features
SET (%s) = (%s)
FROM (SELECT %s FROM features) g'
, cols, vals, aggs);
END
$func$ LANGUAGE plpgsql;
更多解释的相关答案:
- Update multiple columns in a trigger function in plpgsql