Как сделать так, чтобы `id` автоматически устанавливался по запросу вместо `AUTO_INCREMENT`

У меня есть несколько таблиц для разных типов объектов. Однако идентификатор каждого объекта должен быть уникальным не только среди объектов одного типа, но и среди всех объектов разных типов. Другими словами, идентификатор должен быть уникальным в разных таблицах. Чтобы реализовать эту концепцию, я создал специальную таблицу со счетчиком с одним значением и изменил запросы INSERT, чтобы использовать ее. Теперь это выглядит так:

CREATE TABLE next_id (id INT NOT NULL); -- Table-counter
INSERT INTO next_id VALUES (1);         -- The only value that points to the id for the next object

CREATE TABLE object1 (              -- One of object kinds
    id INT NOT NULL PRIMARY KEY,
    mass INT NOT NULL               -- ... Another one specialized for object1 fields
);

CREATE TABLE object2 (              -- Other object kind
    id INT NOT NULL PRIMARY KEY,
    angles INT NOT NULL             -- ... Another one specialized for object2 fields
);

INSERT INTO object1 (id, mass) VALUES (   -- Inserting object1
    (
        SELECT id                         -- Setting it's id by getting it from the counter
        FROM next_id
    ), 5);
UPDATE next_id SET id=id+1;         -- Changing the counter so that the next object has a different id

INSERT INTO object2 (id, angles) VALUES ( -- The same thing, but for other object kind
    (
        SELECT id
        FROM next_id
    ), 3);
UPDATE next_id SET id=id+1;

Но это выглядит очень странно, и я беспокоюсь, что оператор UPDATE может быть выполнен позже планировщиком, что приведет к коллизиям идентификаторов и другим проблемам. Можно ли это изменить, чтобы идентификатор вел себя как AUTO_INCREMENT? Я имею в виду автоматическую установку идентификатора, например:

INSERT INTO object1 (mass) VALUES (5); -- Id is set automatically

«... Меня беспокоит, что оператор UPDATE может быть выполнен планировщиком позже...» -- Нет. Запросы будут выполняться один за другим в указанном вами порядке. Если сценарий запускается в одном сеансе и нет одновременного выполнения этого сценария, все должно быть хорошо.

The Impaler 01.09.2024 14:28

Почему бы не использовать Auto_INcrenet? см. скрипку

nbk 01.09.2024 14:44

@nbk Это интересный способ сделать это, но при этом создается много ненужных строк с последовательностью всех идентификаторов, которые были созданы когда-либо.

ShkiperDesna 01.09.2024 15:02

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

nbk 01.09.2024 15:17

@ShkiperDesna и это одновременно безопасно

nbk 01.09.2024 15:35
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
3
5
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать Triggers вот так

сначала нам нужно создать таблицу next_id

CREATE TABLE next_id (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);

Инициализировать таблицу идентификаторов

INSERT INTO next_id VALUES (NULL);

Теперь создайте триггер для каждой таблицы.

  1. object1
CREATE TRIGGER before_insert_object1
BEFORE INSERT ON object1
FOR EACH ROW
BEGIN
    DECLARE new_id INT;
    SET new_id = (SELECT id FROM next_id FOR UPDATE);
    SET NEW.id = new_id;
    UPDATE next_id SET id = id + 1;
END;
  1. object2
CREATE TRIGGER before_insert_object2
BEFORE INSERT ON object2
FOR EACH ROW
BEGIN
    DECLARE new_id INT;
    SET new_id = (SELECT id FROM next_id FOR UPDATE);
    SET NEW.id = new_id;
    UPDATE next_id SET id = id + 1;
END;

Альтернативно вы можете использовать такие UUID

CREATE TABLE object1 (
    id CHAR(36) NOT NULL PRIMARY KEY,
    mass INT NOT NULL
);

CREATE TABLE object2 (
    id CHAR(36) NOT NULL PRIMARY KEY,
    angles INT NOT NULL
);

Вставка данных с использованием UUID

INSERT INTO object1 (id, mass) VALUES (UUID(), 5);
INSERT INTO object2 (id, angles) VALUES (UUID(), 3);

Вы должны INSERT в триггере, а не SELECT + UPDATE !!!

Akina 01.09.2024 14:38

Где обновление? Есть ли проблемы с ответом?

Hamdallah 01.09.2024 14:58

@Akina Почему плохо использовать SELECT + UPDATE? Я попробовал это только сейчас, и никаких проблем не произошло.

ShkiperDesna 01.09.2024 15:04

@ShkiperDesna Вы не пробовали это в параллельной среде.

Akina 01.09.2024 15:10

Другие вопросы по теме