(一个表)使用序列插入行

时间:2019-06-04 05:26:15

标签: sql postgresql

这个问题是this one的继续。

我有下表egr

+---------+---------+------------+
|  egrid  |  offid  |  groupid   |
+---------+---------+------------+
|    1000 |       1 | 101        |
|    1001 |       1 | 202        |
|    1002 |       2 | 202        |
|    1003 |       2 | 404        |
+---------+---------+------------+

请注意,egrid是一个序列。

我想插入offid 2所没有的缺少的groupid(与offid 1相比)。结果将是:

+---------+---------+------------+
|  egrid  |  offid  |  groupid   |
+---------+---------+------------+
|    1000 |       1 | 101        |
|    1001 |       1 | 202        |
|    1002 |       2 | 202        |
|    1003 |       2 | 404        |
|    1004 |       2 | 101        |   --> new row to insert
+---------+---------+------------+

根据其他问题的答案,我在下面尝试(不起作用)。 我的问题是,该序列随select语句递增。但是,如果有555行且offid = 1,则将增加555次,尽管最后只会插入几行。我正在寻找一种更好的方法。

INSERT INTO egr (egrid, offid, groupid)
  SELECT nextval('seq_egrid'), 2, groupid
    FROM egr
    WHERE offid = 1
  EXCEPT
  SELECT egrid, 2, groupid
    FROM egr
    WHERE offid = 2
ON CONFLICT DO NOTHING;

2 个答案:

答案 0 :(得分:1)

要在添加行的情况下仅递增nextval,可以尝试执行以下操作:

INSERT INTO egr (egrid, offid, groupid)
  SELECT nextval('seq_egrid'), 2, g FROM (
    SELECT groupid as g
      FROM egr
      WHERE offid = 1
    EXCEPT
    SELECT groupid
      FROM egr
      WHERE offid = 2
  ) AS t
ON CONFLICT DO NOTHING;

答案 1 :(得分:0)

您可以使用以下方法生成行:

select o.offid, g.groupid
from (select distinct offid from egr) as o cross join
     (select groupid from egr where offid = 1) g left join
     egr
     on egr.offid = o.offid and
        egr.groupid = g.groupid
where egr.offid is null;

我不会在第一列使用序列,而只是使用serial值,所以我会写:

insert into egr (offid, groupid)
    select o.offid, g.groupid
    from (select distinct offid from egr) as o cross join
         (select groupid from egr where offid = 1) g left join
         egr
         on egr.offid = o.offid and
            egr.groupid = g.groupid
    where egr.offid is null;

然后让数据库分配第一个值。当然,如果使用序列,则可以明确:

insert into egr (egrid, offid, groupid)
    select nextval('seq_egrid'), o.offid, g.groupid
    from (select distinct offid from egr) as o cross join
         (select groupid from egr where offid = 1) g left join
         egr
         on egr.offid = o.offid and
            egr.groupid = g.groupid
    where egr.offid is null;