PostgreSQL,将一个表中的多个记录分配给另一个表中的单个记录

时间:2017-02-02 14:32:09

标签: sql postgresql

我在PostgreSQL中有两个表。捐赠桌子和带桌子的桌子。我想为每个功能分配一个donation_id,但是应该将一些donation_id分配给表中的多个记录,其中的功能基于捐赠表中的ammount。

例如:有人捐赠10,然后每2个功能应分配给功能表中具有相同donation_id的特定donation_id = 5条记录。

我正在寻找更新声明,因为这些功能已经存在并且它们都具有唯一值。将哪个特征分配给哪个捐赠并不重要,只有数量很重要。

捐赠:

donation_id | ammount
=====================
001         | 10
002         | 4

特点:

feature_id  | donation_id | owned
=================================
001         | 000         | false
002         | 000         | false
003         | 000         | false
004         | 000         | false
005         | 000         | false
006         | 000         | false
007         | 000         | false
008         | 000         | false

输出:

feature_id  | donation_id | owned
=================================
001         | 001         | true
002         | 001         | true
003         | 001         | true
004         | 001         | true
005         | 001         | true
006         | 002         | true
007         | 002         | true
008         | 000         | false

1 个答案:

答案 0 :(得分:0)

您可以使用Common Table Expression(或两个临时表,或一些子查询和冗余),玩几个技巧:

  1. 您可以使用CROSS JOIN(即笛卡尔积)和generate_series来获取重复的行。 [我们添加一个row_number()列以便能够区分它们。]
  2. 您可以通过使用表达式获取feature_idLIMIT行数来选择一定数量的功能。我们再次添加row_number()列以区分它们。
  3. 因此,以下代码可以解决问题:

    -- Get a (virtual) table with "donation_id" repeated as many times 
    -- as (amount/2). Trick: use a CROSS JOIN with generate_series
    WITH new_features AS
    (
        SELECT
             donation_id, row_number()  over () AS rn
        FROM
            donations 
            CROSS JOIN generate_series(1, amount/2) AS g(i)
    ),
    -- Right now we know how many rows we want to UPDATE. 
    -- The next SELECT chooses them. Trick: computed LIMIT
    to_update AS
    (
        SELECT
            feature_id, row_number() over () AS rn
        FROM
            features
        WHERE
            NOT owned
        ORDER BY
            feature_id  -- This is arbitrary, it could even not be sorted.
        LIMIT
            (SELECT count(*) FROM new_features)
    )
    -- ... and finally
    UPDATE
        features
    SET
        donation_id = new_features.donation_id, owned = true
    FROM
        to_update
        JOIN new_features USING(rn)
    WHERE
        features.feature_id = to_update.feature_id 
    RETURNING
        features.feature_id, features.donation_id, features.owned ;
    

    您可以在RexTester

    查看

    注意:

    • 我假设feature_id是主键(或备用键:唯一且不为空)。如果不是这样,则需要适当的PK。
    • owned表示donation_id时,可能只有一个NULL而不是not owned列。这样可以保存一个不必更新的列。