2015-05-27 2 views
1

Я хочу, чтобы получить этот результат в моей таблице contacts:В зависимости SERIAL столбец в PostgreSQL

|contact_id | user_id   | user_contact_id  | 
+-----------+------------------+----------------------+ 
| 1  | 1    |   1   | 
+-----------+------------------+----------------------+ 
| 2  | 1    |   2   | 
+-----------+------------------+----------------------+ 
| 3  | 1    |   3   | 
+-----------+------------------+----------------------+ 
| 4  | 2    |   1   | 
+-----------+------------------+----------------------+ 
| 5  | 2    |   2   | 
+-----------+------------------+----------------------+ 
| 6  | 2    |   3   | 
+-----------+------------------+----------------------+ 
| 7  | 3    |   1   | 
+-----------+------------------+----------------------+ 

Я собираюсь вставить только user_id.

INSERT INTO contacts (user_id) VALUES ($user_id); 

contact_id будет автоинкрементным, потому что это serial. Я хочу, чтобы user_contact_id также автоматически заселялся самой БД, поэтому он стабилен на 100% при одновременной записи.

+0

ли значение 'user_contact_id' всегда считая 1-3? – Scopey

+1

Последующие действия в связи с этим предыдущим связанным вопросом. http://stackoverflow.com/questions/30469032/postgresql-inner-queries-with-prepared-statements –

+1

Это ** не тривиально ** из-за проблем с параллелизмом. Вы должны быть очень точными. Просьба уточнить * в вашем вопросе *: Ваша версия Postgres? Ли '(user_id, user_contact_id)' должен быть уникальным или случайным образом обходится в порядке, который можно отличить с помощью 'contact_id'. (Сделал бы это * намного проще). Как бороться с пробелами в 'user_contact_id' из-за' DELETE' и/или 'UPDATE', или это' INSERT'-only? Имеются ли пробелы в последовательности? Вы знаете, что пробелы * должны быть ожидаемыми * в столбцах 'serial' при одновременной нагрузке, правильно? И этот прецедент для * нескольких * или * многих пользователей? –

ответ

0

Вы должны использовать последовательность в качестве значения по умолчанию для вашего user_contact_id. И это именно то, что делает тип столбца SERIAL.

http://www.postgresql.org/docs/9.1/static/datatype-numeric.html http://www.postgresql.org/docs/9.4/static/sql-createsequence.html

последовательности безопасны с одновременной записью.

CREATE TABLE contacts (
    contact_id  SERIAL PRIMARY KEY, 
    user_id   INTEGER, 
    user_contact_id SERIAL 
); 

INSERT INTO contacts (user_id) VALUES 
    (1), (1), (1), (2), (2), (2), (3); 

И вот результаты:

> SELECT * FROM contacts; 
contact_id | user_id | user_contact_id 
------------+---------+----------------- 
      1 |  1 |    1 
      2 |  1 |    2 
      3 |  1 |    3 
      4 |  2 |    4 
      5 |  2 |    5 
      6 |  2 |    6 
      7 |  3 |    7 

> \d contacts 
            Table "public.contacts" 
    Column  | Type |        Modifiers 
-----------------+---------+-------------------------------------------------------------------- 
contact_id  | integer | not null default nextval('contacts_contact_id_seq'::regclass) 
user_id   | integer | 
user_contact_id | integer | not null default nextval('contacts_user_contact_id_seq'::regclass) 
Indexes: 
    "contacts_pkey" PRIMARY KEY, btree (contact_id) 
+1

Мое понимание исходного вопроса заключается в том, что OP хочет, чтобы user_contact_id самостоятельно увеличивал значения на 'user_id'. – fvu

+0

О, я не заметил этого, извините, я просто удалю этот ответ, если это так. –

0
INSERT INTO CONTACTS 
    (user_id, user_contact_id) 
VALUES 
    ($user_id, (SELECT COALESCE(MAX(user_contact_id), 0) + 1 FROM CONTACTS WHERE user_id = $user_id)) 
+0

Майкл - это здорово, но как насчет параллелизма, я собираюсь использовать это, когда у меня есть много клиентов, вставляющих записи в БД – CodeRows

+2

Это также не работает, если есть новый пользователь, так как MAX вернет null и null + 1 == null. –

+0

@SamiKuhmonen thats true, я согласен, у вас есть обходное решение для этого? – CodeRows

0

Как и другие пользователи предложили только sequence -s или serial типа гарантированно будут одновременно безопасными.

Если вам действительно нужно иметь user_contact_id «перезагрузки» каждый user_id может быть, вы могли бы использовать следующий вид:

create view contacts_v as 
select 
    contact_id, 
    user_id, 
    rank() over (partition by user_id order by contact_id) as user_contact_id 
from contacts; 
Смежные вопросы