【问题标题】:Insert multiple rows across 3 tables in 1 query using returned id使用返回的 id 在 1 个查询中跨 3 个表插入多行
【发布时间】:2016-02-03 16:04:59
【问题描述】:

我正在以 3 个表格的形式记录运动比赛数据:

  • 匹配(id,start_time)
  • match_teams(id、match_id、team_id、得分)
  • match_players(id、match_id、team_id、player_id)

每场比赛由几支球队组成,每支球队由几名球员组成(实际上是一个列表)。以team_id和player_id分别作为teams和players表的外键。

使用上面的结构,我需要先插入到matches表中,并使用返回的id传入match_teams和match_players。

this question 之后,我正在使用以下 CTE 来完成此操作,我正在插入一个匹配项:

WITH a AS (INSERT INTO matches (start_time) 
VALUES ('"0001-01-01T00:00:00+00:00"') 
RETURNING id), 
b AS (INSERT INTO match_teams (match_id, team_id, score) 
VALUES 
((SELECT id FROM a), 5, 1), 
((SELECT id FROM a), 6, 2)) 
INSERT INTO match_players (match_id, team_id, player_id) 
VALUES 
((SELECT id FROM a), 5, 3), 
((SELECT id FROM a), 5, 4),
((SELECT id FROM a), 6, 5)
((SELECT id FROM a), 6, 6); 

我想在一个查询中一次插入多个匹配项。我正在使用 offset 和 limit 为球员/球队选择正确的比赛 ID。

WITH a AS (INSERT INTO matches (start_time) 
VALUES 
('"0001-01-01T00:00:00+00:00"'),     -- 1st match
('"0001-01-01T00:00:00+00:00"')      -- 2nd match
RETURNING id), 
b AS (INSERT INTO match_teams (match_id, team_id, score) 
VALUES 
((SELECT id FROM a OFFSET 0 LIMIT 1), 5, 1),     -- 1st match
((SELECT id FROM a OFFSET 0 LIMIT 1), 6, 2),     -- 1st match
((SELECT id FROM a OFFSET 1 LIMIT 1), 5, 2),     -- 2nd match
((SELECT id FROM a OFFSET 1 LIMIT 1), 6, 1))     -- 2nd match
INSERT INTO match_players (match_id, team_id, player_id) 
VALUES 
((SELECT id FROM a OFFSET 0 LIMIT 1), 5, 3),     -- 1st match
((SELECT id FROM a OFFSET 0 LIMIT 1), 6, 4),     -- 1st match
((SELECT id FROM a OFFSET 1 LIMIT 1), 5, 5),     -- 2nd match
((SELECT id FROM a OFFSET 1 LIMIT 1), 6, 6);     -- 2nd match

这可行,但它似乎有点像一个 hacky 解决方案。有没有最佳实践方法来做到这一点?

更新我意识到我有一些多余的列。我已经解决了这个问题,但我认为它不会显着改变问题。我的问题更像是“像这种最佳做法一样使用偏移量和限制吗?”

【问题讨论】:

  • 您可以使用序列(nextval, currval)来避免selectsoffset。虽然我很确定这个查询解决方案根本不是最佳实践。

标签: sql postgresql


【解决方案1】:

是否像这种最佳做法一样使用偏移和限制?

当然不是。这确实效率低下,使用起来非常不方便,尤其是对于大量匹配时。

您可以使用row_number() 选择合适的id 加入teamsplayersteams

with teams (rn, team_ids, scores) as (
    values 
        (1, array[5, 6], array[1, 2]),  -- match #1 in this query
        (2, array[5, 6], array[2, 1])   -- match #2 in this query
    ),
players (rn, team_ids, player_ids) as (
    values 
        (1, array[5, 5, 6, 6], array[3, 4, 5, 6]),
        (2, array[5, 5, 6, 6], array[3, 4, 5, 6])
    ),
ins_matches as (
    insert into matches (start_time) 
    values 
        ('"0001-01-01t00:00:00+00:00"'),
        ('"0001-01-01t00:00:00+00:00"')
    returning id
    ),
matches as (
    select id, row_number() over (order by id) rn
    from ins_matches        -- rn - number of match in this query
    ),
ins_teams as (
    insert into match_teams (match_id, team_id, score) 
    select id, unnest(team_ids), unnest(scores)
    from matches
    join teams using(rn)
    ) 
insert into match_players (match_id, team_id, player_id) 
select id, unnest(team_ids), unnest(player_ids)
from matches
join players using(rn);

【讨论】:

    【解决方案2】:

    就我而言,我有 route_sourcesroutes

    • route_sourcesroute_source_id作为PK
    • routesroute_source_id 作为 FK

    .

    -- GOT ID TO ROUTE_SOURCES FROM SEQUENCE
    int_route_source_id = nextval('traffic.route_sources_route_source_id_seq'::regclass);
    
    -- CREATE NEW RECORD FOR ROUTE_SOURCES
    INSERT INTO traffic.Route_Sources 
        (route_source_id, sql, ini_avl_id, ini_link_id)
    VALUES
        (int_route_source_id, strSQL, A.avl_id, A.link_id, ini_offset); 
    
    -- CREATE THE ROUTE
    INSERT INTO traffic.Routes 
        (route_source_id, seq_id, node_id, link_id, cost)               
    SELECT int_route_source_id, seq, id1 AS node, id2 AS edge, cost::numeric(11,4)
        FROM pgr_trsp; 
    

    【讨论】:

      猜你喜欢
      • 2023-03-28
      • 1970-01-01
      • 2014-01-26
      • 2017-02-14
      • 2013-02-27
      • 2014-06-04
      • 2019-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多