基于另一列的PostgreSQL序列

[英]PostgreSQL sequence based on another column


Lets say I have a table as such:

假设我有一张这样的桌子:

Column   |     Type    |                        Notes
---------+------------ +----------------------------------------------------------
 id      | integer     | An ID that's FK to some other table
 seq     | integer     | Each ID gets its own seq number
 data    | text        | Just some text, totally irrelevant.

id + seq is a combined key.

id + seq是一个组合键。

What I'd like to see is:

我想看到的是:

ID  | SEQ   |                        DATA
----+------ +----------------------------------------------
 1  | 1     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 1  | 2     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 1  | 3     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 1  | 4     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 2  | 1     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 3  | 1     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 3  | 2     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 3  | 3     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 3  | 4     | Quick brown fox, lorem ipsum, lazy dog, etc etc.

As you can see, a combination of id and seq is unique.

如您所见,id和seq的组合是唯一的。

I'm not sure how to set up my table (or insert statement?) to do this. I'd like to insert id and data, resulting in seq being a sub-sequence dependent on id.

我不知道如何设置表(或插入语句?)我想插入id和数据,导致seq是一个依赖于id的子序列。

8 个解决方案

#1


14  

You could use a window function to assign your SEQ values, something like:

您可以使用窗口函数来分配SEQ值,比如:

INSERT INTO YourTable
    (ID, SEQ, DATA)
    SELECT ID, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY DATA), DATA
        FROM YourSource

#2


14  

No problem! We're going to make two tables, things and stuff. stuff will be the table you describe in your question, and things is the one it refers to:

没问题!我们要做两张桌子,一些东西。在你的问题中,内容将是你所描述的表格,而事物则是你所提到的:

CREATE TABLE things (
    id serial primary key,
    name text
);

CREATE TABLE stuff (
    id integer references things,
    seq integer NOT NULL,
    notes text,
    primary key (id, seq)
);

Then we'll set things up with a trigger that will create a new sequence every time a row is created:

然后,我们将设置一个触发器,每当创建一行时,该触发器将创建一个新的序列:

CREATE FUNCTION make_thing_seq() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
begin
  execute format('create sequence thing_seq_%s', NEW.id);
  return NEW;
end
$$;

CREATE TRIGGER make_thing_seq AFTER INSERT ON things FOR EACH ROW EXECUTE PROCEDURE make_thing_seq();

Now we'll end up with thing_seq_1, thing_seq_2, etc, etc...

现在我们将以thing_seq_1、thing_seq_2等结束……

Now another trigger on stuff so that it uses the right sequence each time:

这是另一个触发事件,每次都使用正确的序列:

CREATE FUNCTION fill_in_stuff_seq() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
begin
  NEW.seq := nextval('thing_seq_' || NEW.id);
  RETURN NEW;
end
$$;

CREATE TRIGGER fill_in_stuff_seq BEFORE INSERT ON stuff FOR EACH ROW EXECUTE PROCEDURE fill_in_stuff_seq();

That'll ensure that when rows go into stuff, the id column is used to find the right sequence to call nextval on.

这将确保当行进入内容时,id列用于找到调用nextval的正确序列。

Here's a demonstration:

这里有一个示范:

test=# insert into things (name) values ('Joe');
INSERT 0 1
test=# insert into things (name) values ('Bob');
INSERT 0 1
test=# select * from things;
 id | name
----+------
  1 | Joe
  2 | Bob
(2 rows)

test=# \d
              List of relations
 Schema |     Name      |   Type   |  Owner
--------+---------------+----------+----------
 public | stuff         | table    | jkominek
 public | thing_seq_1   | sequence | jkominek
 public | thing_seq_2   | sequence | jkominek
 public | things        | table    | jkominek
 public | things_id_seq | sequence | jkominek
(5 rows)

test=# insert into stuff (id, notes) values (1, 'Keychain');
INSERT 0 1
test=# insert into stuff (id, notes) values (1, 'Pet goat');
INSERT 0 1
test=# insert into stuff (id, notes) values (2, 'Family photo');
INSERT 0 1
test=# insert into stuff (id, notes) values (1, 'Redundant lawnmower');
INSERT 0 1
test=# select * from stuff;
 id | seq |        notes
----+-----+---------------------
  1 |   1 | Keychain
  1 |   2 | Pet goat
  2 |   1 | Family photo
  1 |   3 | Redundant lawnmower
(4 rows)

test=#

#3


2  

If seq reflects (or should reflect) the order in which the rows are inserted, I'd rather use a timestamp that gets populated automatically and generate the sequence number on the fly when selecting the rows using row_number():

如果seq反映(或应该反映)插入行的顺序,我宁愿使用自动填充的时间戳,并在使用row_number()选择行时动态生成序列号:

create table some_table
( 
  id          integer   not null,
  inserted_at timestamp not null default current_timestamp,
  data text
);

The to get the seq column, you can do:

要获得seq专栏,你可以:

select id,  
       row_number() over (partition by id order by inserted_at) as seq,
       data
from some_table
order by id, seq;

The select is however going to be a bit slower compared to using a persisted seq column (especially with an index on id, seq).

然而,与使用持久化seq列相比,select要慢一些(特别是对于id上的索引,seq)。

If that becomes a problem you can either look into using a materialized view, or adding the seq column and then updating it on a regular basis (I would not do this in a trigger for performance reasons).

如果这成为一个问题,您可以使用物化视图查看,或者添加seq列,然后定期更新它(出于性能原因,我不会在触发器中这样做)。

SQLFiddle example: http://sqlfiddle.com/#!15/db69b/1

SQLFiddle示例:http://sqlfiddle.com/ ! 15 / db69b / 1

#4


1  

You can use Sequences either It's also a great option

你可以使用序列,它也是一个很好的选择

CREATE SEQUENCE SEQ_NUM START 1;

INSERT INTO TABLE_NAME(ID, SEQ, DATA) VALUES(**SOME_ID**, SELECT nextval('SEQ_NUM') AS SEQ_NUM, **SOME DATA**);

Now In this case the Sequence "SEQ_NUM" value will be managed totally by PostgreSQL, Now you dont have to manage any counter or anything else.

在这种情况下,序列“SEQ_NUM”值将完全由PostgreSQL管理,现在您不必管理任何计数器或其他任何东西。

#5


0  

Just a guess.

只是一个猜测。

INSERT INTO TABLE (ID, SEQ, DATA)
VALUES
(
 IDVALUE,
 (SELECT max(SEQ) +1 FROM TABLE WHERE ID = IDVALUU),
 DATAVALUE
);

#6


0  

Here's a simple way using standard SQL:

这里有一种使用标准SQL的简单方法:

INSERT INTO mytable (id, seq, data)
SELECT << your desired ID >>,
       COUNT(*) + 1,
       'Quick brown fox, lorem ipsum, lazy dog, etc etc.'
FROM mytable
WHERE id = << your desired ID (same as above) >>;

See SQL Fiddle Demo.

查看演示SQL小提琴。

(If you wanted to be a bit cleverer you could consider creating a trigger to update the row using the same method immediately after an insert.)

(如果您想更聪明一点,可以考虑创建一个触发器,在插入之后立即使用相同的方法更新行。)

#7


-1  

PostgreSQL supports grouped unique columns, as such:

PostgreSQL支持分组的唯一列,如下所示:

CREATE TABLE example (
    a integer,
    b integer,
    c integer,
    UNIQUE (a, c)
);

See PostgreSQL Documentation - Section 5.3.3

参见PostgreSQL文档——第5.3.3节。

Easy :-)

容易:-)

#8


-1  

I don't have any postgresql-specific experience, but can you use a subquery in your insert statement? Something like, in Mysqlish,

我没有任何特定于postgresql的经验,但是可以在insert语句中使用子查询吗?Mysqlish之类的,

INSERT INTO MYTABLE SET 
   ID=4, 
   SEQ=(  SELECT MAX(SEQ)+1 FROM MYTABLE WHERE ID=4  ),
   DATA="Quick brown fox, lorem ipsum, lazy dog, etc etc."

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2011/07/25/3a65b5f7731e2029b220e4d6d4c427a2.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号