#postgresql
#postgresql
Вопрос:
У меня есть таблица следующего вида
|GroupID | UserID |
--------------------
|1 | 1 |
|1 | 2 |
|1 | 3 |
|2 | 1 |
|2 | 2 |
|3 | 20 |
|3 | 30 |
|5 | 200 |
|5 | 100 |
По сути, это создает «группу», с которой ассоциируются идентификаторы пользователей, поэтому, когда я хочу запросить членов группы, я могу вызвать таблицу.
Пользователи имеют возможность покинуть группу и создать новую.
Когда все пользователи покидают группу, в моей таблице больше нет этого groupId.
Давайте представим, что это для приложения чата, в котором пользователи могут постоянно закрывать и открывать чаты, идентификаторы групп будут складываться очень быстро, но количество чатов реально не достигнет миллионов чатов с сотнями пользователей.
Я хотел бы переработать идентификационные номера групп таким образом, чтобы при вставке новой записи, если группа 4 не используется (как в приведенном выше случае), она присваивалась.
Комментарии:
1. Эти идентификаторы являются суррогатными ключами. Никто не должен их видеть / заботиться об их значениях. Просто оставьте их в покое. Если вы хотите что-то отобразить и вам не нравятся «group345876» или «user9013758235», добавьте поддержку отображаемых имен, удобочитаемых человеком.
2. Моя проблема в том, что 9223372036854775807 звучит как большое число, пока не пройдет несколько лет.
3. Просто перестаньте беспокоиться. Если у вас будет 1 миллиард пользователей, и они будут создавать новый идентификатор каждую секунду каждого часа каждого дня, на исчерпание идентификаторов уйдет почти 300 лет. Если моя математика верна.
Ответ №1:
Есть веские причины не делать этого, но в PostgreSQL это довольно просто. Этот метод — использование generate_series() для поиска пробелов в последовательности — полезен и в других контекстах.
WITH group_id_range AS (
SELECT generate_series((SELECT MIN(group_id) FROM groups),
(SELECT MAX(group_id) FROM groups)) group_id
)
SELECT min(gir.group_id)
FROM group_id_range gir
LEFT JOIN groups g ON (gir.group_id = g.group_id)
WHERE g.group_id IS NULL;
Этот запрос вернет NULL, если в таблице «группы» нет пробелов или если в ней вообще нет строк. Если вы хотите использовать это для возврата следующего идентификационного номера группы независимо от состояния таблицы «группы», используйте это вместо этого.
WITH group_id_range AS (
SELECT generate_series(
(COALESCE((SELECT MIN(group_id) FROM groups), 1)),
(COALESCE((SELECT MAX(group_id) FROM groups), 1))
) group_id
)
SELECT COALESCE(min(gir.group_id), (SELECT MAX(group_id) 1 FROM groups))
FROM group_id_range gir
LEFT JOIN groups g ON (gir.group_id = g.group_id)
WHERE g.group_id IS NULL;