2017-02-21 53 views
0

У меня есть база данных PostgreSQL Версии 9.5.0.POSTGRES последовательность TRIGGER на не первичный ключ

В таблице UserComments был создан как:

create table UserComments ( 
    userId integer, 
    commentNr integer, 
    comment text, 
    UNIQUE (userId, commentNr) 
); 

таблица не может быть изменена ни я могу добавить дополнительную таблицу.

Я хотел бы сделать последовательность (иными словами: значение автоматического увеличения) на commentNr в зависимости от суммы userId записей. Для каждой новой записи с тем же userId ее значение должно быть увеличено.
Пример:

 
userId | commentNr | comment 
-------|-----------|--------- 
1  | 1  | blabla 
1  | 2  | more bla 
2  | 1  | myownbla 
1  | 3  | evenmorebla 

Я уже нашел ответы на некоторые вопросы с «триггеры» и «функций окна», но и не было на самом деле работает для меня, так как я не разрешается изменять таблицу. Лучшее решение будет триггером на каждом INSERT, который автоматически counts/вычисляет commentNr таким образом я могу добавить новую запись с

insert into user(userId, comment) values ('1', 'bla'); 

Любая помощь будет оценена.

+0

'primary key (id),' :: в вашей таблице нет столбца 'id'. Пожалуйста, напишите реальный код. – joop

+0

Вы правы - первичный ключ для этого примера является ненужным. –

ответ

0

Для автоматического расчета commentNr поля вы можете использовать триггер:

CREATE INDEX i1 ON UserComments (userId, commentNr DESC); 

CREATE OR REPLACE FUNCTION set_commentNr() RETURNS TRIGGER AS $sql$ 
BEGIN 
    NEW.commentNr = coalesce(max(commentNr) + 1, 1) FROM UserComments WHERE UserId = NEW.userID; 
    RETURN NEW; 
END; 
$sql$ LANGUAGE plpgsql STABLE; 


CREATE TRIGGER ins_comment BEFORE INSERT ON UserComments FOR EACH ROW EXECUTE PROCEDURE set_commentNr(); 

Маленький тест:

insert into userComments (userId, comment) values ('1', 'bla'); 
insert into userComments (userId, comment) values ('1', 'bla'); 
insert into userComments (userId, comment) values ('2', 'bla'); 
insert into userComments (userId, comment) values ('1', 'bla'); 
insert into userComments (userId, comment) values ('2', 'bla'); 

SELECT * FROM userComments; 

userid | commentnr | comment 
--------+-----------+--------- 
     1 |   1 | bla 
     1 |   2 | bla 
     2 |   1 | bla 
     1 |   3 | bla 
     2 |   2 | bla 
(5 rows) 

Индекс i1 создан для повышения производительности при расчете следующего значения:

               QUERY PLAN                
------------------------------------------------------------------------------------------------------------------------------------- 
Result (cost=4.17..4.18 rows=1 width=4) (actual time=0.032..0.032 rows=1 loops=1) 
    InitPlan 1 (returns $0) 
    -> Limit (cost=0.15..4.17 rows=1 width=4) (actual time=0.026..0.026 rows=1 loops=1) 
      -> Index Only Scan using i1 on usercomments (cost=0.15..24.27 rows=6 width=4) (actual time=0.021..0.021 rows=1 loops=1) 
       Index Cond: ((userid = 1) AND (commentnr IS NOT NULL)) 
       Heap Fetches: 1 
Planning time: 0.238 ms 
Execution time: 0.095 ms 
0

Для простого случая, такого как это, нет необходимости создавать триггер. Правильная последовательность может быть вычислена в CTE или в подзапросе и вставлена.

Примечание: При использовании ниже SQL, вставленного userId должен быть указан дважды

INSERT INTO "user" ("userId", "commentNr", "comment") (
WITH 
    nextval AS (
    SELECT COALESCE(MAX("commentNr"),0)+1 commentNr 
    FROM "user" 
    WHERE "userId" = '1' 
) 
SELECT '1', nextval.commentNr, 'bla' 
FROM nextval 
);