CREATE TABLE t_a
(
a_id SERIAL PRIMARY KEY,
str VARCHAR(50)
)
CREATE TABLE t_b
(
b_id SERIAL PRIMARY KEY,
a_id_fk INTEGER REFERENCES (t_a(a_id),
)
使用上面的表格,我想SELECT a_id_fk FROM t_b WHERE b_id = 1
,然后使用序列中的下一个a_id_fk
更新a_id
,但如果我在可用的{{}}结束时{1}}我循环回到第一个。所有这一切都有多人查询/更新a_id
中的特定行。
如果有帮助,我正在处理的场景是多个站点共享一个共同的单词列表,但是当每个站点的每个用户抓取一个单词时,单词列表中的站点索引将被移动到下一个单词,直到它会结束然后它会循环回到开头。
有没有办法在单个查询中执行此操作?如果没有,最好的办法是什么?我可以处理大部分逻辑,当我用完了让我难倒的ID时,它会循环回来。
答案 0 :(得分:0)
你可以使用像
这样复杂的东西UPDATE t_b
SET a_id_fk = COALESCE(
(SELECT MIN(a_id) FROM t_a WHERE a_id > t_b.a_id_fk),
(SELECT MIN(a_id) FROM t_a))
WHERE b_id = :b_id
但如果我得到了这样的要求,我可能会维护一个辅助表,将a_id映射到循环中的下一个a_id ...
答案 1 :(得分:0)
这个比@pdw的解决方案更优雅(恕我直言):
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE t_a
( a_id SERIAL PRIMARY KEY
, str VARCHAR(50)
);
CREATE TABLE t_b
( b_id SERIAL PRIMARY KEY
, a_id_fk INTEGER REFERENCES t_a(a_id)
);
INSERT INTO t_a(str)
SELECT 'Str_' || gs::text
FROM generate_series(1,10) gs
;
INSERT into t_b(a_id_fk)
SELECT a_id FROM t_a
ORDER BY a_id
;
-- EXPLAIN ANALYZE
WITH src AS (
SELECT a_id AS a_id
, min(a_id) OVER (order BY a_id) AS frst
, lead(a_id) OVER (order BY a_id) AS nxt
FROM t_a
)
UPDATE t_b dst
SET a_id_fk = COALESCE(src.nxt, src.frst)
FROM src
WHERE dst.a_id_fk = src.a_id
AND dst.b_id IN ( 3, 10)
;
SELECT * FROM t_b
ORDER BY b_id
;
结果:
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
CREATE TABLE
INSERT 0 10
INSERT 0 10
UPDATE 2
b_id | a_id_fk
------+---------
1 | 1
2 | 2
3 | 4
4 | 4
5 | 5
6 | 6
7 | 7
8 | 8
9 | 9
10 | 1
(10 rows)