Можно ли использовать последовательность PG на одной записи?

Предоставляет ли PostgreSQL 9.2+ любую функцию, позволяющую генерировать последовательность с именами, помещенными в определенное значение? Например:

.. | user_id | seq_id | body | ... ---------------------------------- - | 4 | 1 | "abc...." - | 4 | 2 | "def...." - | 5 | 1 | "ghi...." - | 5 | 2 | "xyz...." - | 5 | 3 | "123...." 

Это было бы полезно для создания пользовательских URL-адресов для пользователя:

 domain.me/username_4/posts/1 domain.me/username_4/posts/2 domain.me/username_5/posts/1 domain.me/username_5/posts/2 domain.me/username_5/posts/3 

Я ничего не нашел в документах PG (относительно функций последовательности и последовательности), чтобы сделать это. Являются ли подзапросы в INSERT или с пользовательскими функциями PG единственными другими параметрами?

    Может быть, этот ответ немного вне трасс, но я бы подумал о разделении данных и предоставлении каждому user собственной секционированной таблицы для posts .

    В настройке немного накладных расходов, так как вам понадобятся триггеры для управления операторами DDL для разделов, но эффективно приведут к тому, что каждый пользователь будет иметь свою собственную таблицу сообщений вместе со своей собственной последовательностью, чтобы иметь возможность лечить все как один большой стол.

    Общий смысл концепции …

     psql# CREATE TABLE posts (user_id integer, seq_id integer); CREATE TABLE psql# CREATE TABLE posts_001 (seq_id serial) INHERITS (posts); CREATE TABLE psql# CREATE TABLE posts_002 (seq_id serial) INHERITS (posts); CREATE TABLE psql# INSERT INTO posts_001 VALUES (1); INSERT 0 1 psql# INSERT INTO posts_001 VALUES (1); INSERT 0 1 psql# INSERT INTO posts_002 VALUES (2); INSERT 0 1 psql# INSERT INTO posts_002 VALUES (2); INSERT 0 1 psql# select * from posts; user_id | seq_id ---------+-------- 1 | 1 1 | 2 2 | 1 2 | 2 (4 rows) 

    Я оставил некоторые довольно важные ограничения CHECK в приведенной выше настройке, убедитесь, что вы прочитали документы о том, как используются эти типы настроек

    Вы можете использовать подзапрос в INSERT как демонстрирует @Clodoaldo . Однако это нарушает характер последовательности как безопасный для использования в параллельных транзакциях . Это решение может и может привести к условиям гонки и, в конечном счете, дублировать ключевые нарушения.

    Вы должны пересмотреть свой подход . Только одна простая последовательность для вашей таблицы и объедините ее с user_id чтобы получить user_id порядок сортировки.

    Вы всегда можете генерировать пользовательские URL-адреса с нужными номерами с помощью row_number() с помощью простого запроса:

     SELECT format('domain.me/username_%s/posts/%s' ,user_id ,row_number() OVER (PARTITION BY user_id ORDER BY seq_id) ) FROM t; 

    -> SQLfiddle .

     insert into t values (user_id, seq_id) values (4, (select coalesce(max(seq_id), 0) + 1 from t where user_id = 4)) 

    Проверьте наличие дублирующей ошибки первичного ключа в интерфейсе и повторите попытку, если необходимо.

    Обновить

    Хотя советы @Erwin разумны, то есть одна последовательность с упорядочением в выбранном запросе, это может быть дорого.

    Если вы не используете последовательность, нет никакого разрыва в характере последовательности. Также это не приведет к дублированию ключевого нарушения. Чтобы продемонстрировать это, я создал таблицу и ввел в нее скрипт python. Я запустил 3 параллельных экземпляра вставки скрипта как можно быстрее. И это просто работает.

    В этих столбцах таблица должна иметь первичный ключ:

     create table t ( user_id int, seq_id int, primary key (user_id, seq_id) ); 

    Сценарий python:

     #!/usr/bin/env python import psycopg2, psycopg2.extensions query = """ begin; insert into t (user_id, seq_id) values (4, (select coalesce(max(seq_id), 0) + 1 from t where user_id = 4)); commit; """ conn = psycopg2.connect('dbname=cpn user=cpn') conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE) cursor = conn.cursor() for i in range(0, 1000): while True: try: cursor.execute(query) break except psycopg2.IntegrityError, e: print e.pgerror cursor.execute("rollback;") cursor.close() conn.close() 

    После параллельного запуска:

     select count(*), max(seq_id) from t; count | max -------+------ 3000 | 3000 

    Как и ожидалось. Я разработал, по крайней мере, два приложения, использующих эту логику, и один из них старше 13 лет и никогда не проигрывал. Я признаю, что если вы Facebook или какой-то другой гигант, тогда у вас может быть проблема.

    Да:

     CREATE TABLE your_table ( column type DEFAULT NEXTVAL(sequence_name), ... ); 

    Подробнее здесь: http://www.postgresql.org/docs/9.2/static/ddl-default.html