Эффективная вставка строки и строки внешней таблицы, если она не существует - PullRequest
0 голосов
/ 12 января 2019

Аналогично этот вопрос и это решение для PostgreSQL (в частности "ВСТАВИТЬ пропущенные строки FK одновременно"):

Предположим, я создаю адресную книгу с таблицей "Группы" и таблицей "Контакты". Когда я создаю новый контакт, я могу захотеть поместить его в группу одновременно. Так что я мог сделать:

INSERT INTO Contact VALUES (
  "Bob",
  (SELECT group_id FROM Groups WHERE name = "Friends")
)

Но что, если группа "Друзья" еще не существует? Можем ли мы эффективно вставить эту новую группу?

Очевидная вещь - сделать SELECT, чтобы проверить, существует ли группа уже; если не сделать вставку. Затем сделайте ВСТАВКУ в Контакты с помощью ВЫБРАТЬ выше.

Или я могу заставить Group.name быть УНИКАЛЬНЫМ, сделать INSERT ИЛИ IGNORE, а затем ВСТАВИТЬ в Контакты с помощью под-SELECT.

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

Я предполагаю, что в одном запросе нет способа сделать это, поскольку INSERT ничего не возвращает и не может использоваться в подзапросе. Правильна ли эта интуиция? Какова лучшая практика здесь?

1 Ответ

0 голосов
/ 12 января 2019

Я предполагаю, что нет способа сделать это в одном запросе, так как INSERT ничего не возвращает и не может использоваться в подзапросе. В том, что интуиция верна?

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

Например, рассмотрим следующий

Чисто для удобства изготовления демо: -

DROP TRIGGER IF EXISTS add_group_if_not_exists;
DROP TABLE IF EXISTS contact;
DROP TABLE IF EXISTS groups;

Однократная настройка SQL: -

CREATE TABLE IF NOT EXISTS groups (id INTEGER PRIMARY KEY, group_name TEXT UNIQUE);
INSERT INTO groups VALUES(-1,'NOTASSIGNED');
CREATE TABLE IF NOT EXISTS contact (id INTEGER PRIMARY KEY, contact TEXT, group_to_use TEXT, group_reference TEXT DEFAULT -1 REFERENCES groups(id));
CREATE TRIGGER IF NOT EXISTS add_group_if_not_exists 
AFTER INSERT ON contact
BEGIN
 INSERT OR IGNORE INTO groups (group_name) VALUES(new.group_to_use);
 UPDATE contact SET group_reference = (SELECT id FROM groups WHERE group_name = new.group_to_use), group_to_use = NULL WHERE id = new.id;  
END;

SQL, который будет использоваться на постоянной основе: -

INSERT INTO contact (contact,group_to_use) VALUES
        ('Fred','Friends'),
        ('Mary','Family'),
        ('Ivan','Enemies'),
        ('Sue','Work colleagues'),
        ('Arthur','Fellow Rulers'),
        ('Amy','Work colleagues'),
        ('Henry','Fellow Rulers'),
        ('Canute','Fellow Ruler')
;
  • Количество значений и фактические значения будут различаться.

SQL Просто для демонстрации результата

SELECT * FROM groups;
SELECT contact,group_name FROM contact JOIN groups ON group_reference = groups.id;

Результаты

В результате: -

1) Группы (отмечая, что группа «NOTASSIGNED» является неотъемлемой частью работы вышеупомянутого и, следовательно, добавляется изначально): -

enter image description here

  • нужно быть осторожным в отношении ошибок вроде (Товарищ правитель вместо товарищей правителей)
  • -1 , потому что это не будет автоматически генерируемое нормальное значение.

2) Контакты с соответствующей группой: -

enter image description here

Эффективная вставка

Скорее всего, это будет обсуждаться отсюда до бесконечности, так что я оставляю это на усмотрение ситтеров / разрушителей забора :). Однако некоторые соображения: -

  • Он работает и, кажется, делает то, что хотел.
  • Это немного расточительно из-за дополнительной потраченной впустую колонки.
  • Он пытается свести к минимуму потери путем изменения столбца на пустую строку (NULL может быть даже более эффективным, но для некоторых это может сбить с толку)
  • Очевидно, что по сравнению с альтернативами, вероятно, будут накладные расходы, незначительные (возможно, важные, если вы извлекали каждого пользователя Facebook), но если это ввод пользователя, вероятно, не имеет значения.

Какая лучшая практика здесь?

Снова заборы. :)

Примечание Надеемся, что это очевидно, но операторы DROP приведены исключительно для удобства и что все другие SQL вплоть до INSERT запускаются один раз настроить таблицы и триггеры при подготовке к одиночной вставке который добавляет группу при необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...