PostgreSQL:选择字段值并使用第二个表中的下一个值进行更新

时间:2014-07-02 20:38:16

标签: sql postgresql

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时,它会循环回来。

2 个答案:

答案 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)