我有以下架构:
DROP SCHEMA IF EXISTS s CASCADE;
CREATE SCHEMA s;
CREATE TABLE "s"."t1"
(
"c1" BigSerial PRIMARY KEY,
"c2" BigInt NOT NULL,
"c3" BigInt
)
WITH (OIDS=FALSE);
INSERT INTO s.t1 (c2, c3) VALUES (10, 100);
INSERT INTO s.t1 (c2, c3) VALUES (20, 200);
INSERT INTO s.t1 (c2, c3) VALUES (30, 300);
INSERT INTO s.t1 (c2, c3) VALUES (40, 400);
PREPARE updateplan (BigInt, BigInt) AS
update s.t1
SET c3 = $2
WHERE c2 = $1;
EXECUTE updateplan (20, 250);
PREPARE updatearrayplan(BigInt[], BigInt[]) AS
for i in size($1)
DO
update s.t1
SET c3 = $2[$i]
WHERE c2 = $1[$i]
END FOR
EXECUTE updatearrayplan({20, 30}, {275, 375})
/* 20, 200 -> 20, 275 */
/* 30, 300 -> 30, 375 */
执行updatearrayplan后,我希望行具有这些值20 - > 275,30> 375
有没有办法更新多个行,并将不同的列值作为数组传入。还可以保证数组的顺序得以维持。
答案 0 :(得分:1)
尝试:
WITH arrays AS(
SELECT * from
unnest(
ARRAY[20, 30],
ARRAY[275, 375]
) as xy(x,y)
)
UPDATE t1
SET c3 = a.y
FROM arrays a
WHERE c2 = a.x;
在此处查看unnest
功能的说明:click
修改强>
@kordiroko对不起。我试着整天修改你的解决方案。 无法使其发挥作用。
可能是你有一个较旧的PostgreSQL版本。我在9.5版本上进行了测试,只需几分钟就能完成它,只需复制/粘贴并更改查询中的两个参数:
create table t1(
c2 BIGINT,
c3 bigint
);
insert into t1( c2, c3 )
select x, x * 100
from generate_series( 1,1000000 ) x;
CREATE OR REPLACE FUNCTION updatefunc1(BigInt[], BigInt[])
RETURNS void as $$
BEGIN
FOR i IN array_lower($1, 1) .. array_upper($1, 1)
LOOP
update t1
SET c3 = $2[i]
WHERE c2 = $1[i];
END LOOP;
END;
$$
LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION updatefunc2(BigInt[], BigInt[])
RETURNS void as $$
BEGIN
WITH arrays AS(
SELECT * from
unnest( $1, $2 ) as xy(x,y)
)
UPDATE t1
SET c3 = a.y
FROM arrays a
WHERE c2 = a.x;
END;
$$
LANGUAGE plpgsql;
select updatefunc1(ARRAY[20], ARRAY[275]);
select updatefunc2(ARRAY[30], ARRAY[555]);
select * from t1 where c2 in (20,30);
如果这是正确的或有更好的解决方案,请告诉我。
这是非常正确的但是......它有点慢。
我测试了你的功能只有100条记录:
select updatefunc1(
array( select * from generate_series(1,100)),
array( select 22222 from generate_series(1,100))
);
花了12秒钟:
结果(成本= 20.00..20.31行= 1宽度= 0)(实际 时间= 12259.095..12259.096 rows = 1次循环= 1)输出: updatefunc1(($ 0):: bigint [],($ 1):: bigint [])InitPlan 1(返回$ 0)
现在将它与我的功能进行比较,但是对于100.000记录:
select updatefunc2(
array( select * from generate_series(1,100000)),
array( select 22222 from generate_series(1,100000))
);
结果是1秒150毫秒:
结果(成本= 20.00..20.31行= 1宽度= 0)(实际 time = 1150.018..1150.123 rows = 1 loops = 1)输出: updatefunc2(($ 0):: bigint [],($ 1):: bigint [])InitPlan 1(返回$ 0)
以上结果表明,您的功能是:
(12/100)/(1.150 / 100000)= 10434,78
次slooooooooooooooooooooooooooweeeeeeeeeeeeeeeeeeeeeeeeer,
在%中,这只是 1043400%更慢
编辑2
我的版本是9.2.15。它会引发语法错误
以下版本应该适用于PostgreSQL的早期版本:
CREATE OR REPLACE FUNCTION updatefunc3(BigInt[], BigInt[])
RETURNS void as $$
BEGIN
WITH arrays AS(
SELECT arr1[ rn ] as x, arr2[ rn ] as y
FROM (
SELECT $1 as arr1, $2 as arr2, generate_subscripts($1, 1) As rn
) x
)
UPDATE t1
SET c3 = a.y
FROM arrays a
WHERE c2 = a.x;
END;
$$
LANGUAGE plpgsql;
select updatefunc3(ARRAY[40,82,77], ARRAY[333,654]);
select * from t1 where c2 in (40,82,77);
uptadint 100,000行的速度测试是:
select updatefunc3(
array( select * from generate_series(1,100000)),
array( select 22222 from generate_series(1,100000))
);
结果(成本= 20.00..20.31行= 1宽度= 0)(实际 time = 1361.358 .. 1361.460 rows = 1 loops = 1)输出: updatefunc3(($ 0):: bigint [],($ 1):: bigint [])InitPlan 1(返回$ 0)
更新100k行的时间低于1.5秒
编辑3
@kordiko:你能告诉我为什么你的查询要好得多。 我的函数遍历每一行并逐个更新元素。 您的功能似乎也是这样做的。这就是全部 在查询中同时更新等效行。
这是因为我的函数运行只有一个更新命令,无论数组中的元素数量是多少,而您的函数逐个更新元素 - 对于100个元素,它运行100个更新命令。对于1000个元素,它运行1000个更新命令
我已经在一个包含1000000行的表上完成了测试,但是没有任何索引。在我的函数中,更新仅读取表内容一次(执行全表扫描),并更新匹配行。您的功能执行100次更新,每次更新都进行全表扫描
如果您在col2
上创建并编制索引,那么函数的速度会急剧增加,请参阅下面的测试(请注意,此测试中的许多元素从100增加到100000:
create INDEX t1_c2_ix on t1( c2 );
select updatefunc1(
array( select * from generate_series(1,100000)),
array( select 22222 from generate_series(1,100000))
);
Result (cost=20.00..20.31 rows=1 width=0) (actual time=**3430.536**..3430.636 rows=1 loops=1)
Output: updatefunc1(($0)::bigint[], ($1)::bigint[])
InitPlan 1 (returns $0)
现在时间只有约3.5秒。
并在创建索引后测试我的函数:
select updatefunc3(
array( select * from generate_series(1,100000)),
array( select 22222 from generate_series(1,100000))
);
结果(成本= 20.00..20.31行= 1宽度= 0)(实际时间= 1270.619。 .1270.724行= 1个循环= 1) 输出:updatefunc3(($ 0):: bigint [],($ 1):: bigint []) InitPlan 1(返回$ 0)
时间保持不变,但仍然比你的功能快100%。
答案 1 :(得分:0)
我的回答:
CREATE OR REPLACE FUNCTION s.updatefunc1(BigInt[], BigInt[])
RETURNS void as $$
BEGIN
FOR i IN array_lower($1, 1) .. array_upper($1, 1)
LOOP
update s.t1
SET c3 = $2[i]
WHERE c2 = $1[i];
END LOOP;
END;
$$
LANGUAGE plpgsql;
select s.updatefunc1(ARRAY[20], ARRAY[275]);
这确实有效。我得到了我想要的答案:
SELECT c2, c3 FROM s.t1;
c2 | c3
----+-----
10 | 100
30 | 300
40 | 400
20 | 275 --> Updated
如果这是正确的或有更好的解决方案,请告诉我。