SQL вставить внешний ключ, если не существует

#mysql #sql #json #duplicates #sql-insert

#mysql #sql #json #дубликаты #sql-вставка

Вопрос:

Предположим, у меня есть таблица user :

 PK id: int
firstname: varchar
lastname: varchar
FK group_id: int
  

И таблица group :

 PK id: int
name: varchar
  

Теперь я хочу иметь возможность отправлять на сервер объект student JSON, который содержит:

 {
    "firstname": "john",
    "lastname": "doe",
    "group": "group_name"
}
  

Как вставить его в таблицы? Как я могу убедиться, что строка с «имя_группы» существует, и если нет, создайте ее, а затем и только тогда вставьте ученика с соответствующим FK group_id?

Что бы я сделал, это что-то вроде:

  1. выберите идентификатор из группы, где name=»имя_группы»
  2. если не существует: вставить в значения группы («имя_группы»)
  3. вставить в пользовательские значения («john», «doe», the_existing_or_newly_inserted_group_id)

Но это кажется немного излишним с точки зрения количества запросов.

Ответ №1:

В MySQL вы можете сделать это всего двумя операторами:

 insert into groups (group_name) 
select s.group_name
from (select :group_name as group_name) s
where not exists (select 1 from groups g where g.group_name = s.group_name);

insert into users (firstname, lastname, group_id)
select :firstname, :lastname, g.group_id
from groups g
where g.group_name = :group_name;
  

Первый оператор создает новую группу, если она еще не существует. Второй оператор восстанавливает идентификатор группы и вставляет информацию о пользователе.

Для правильной работы group_name в таблице должен быть уникальный ключ groups .

Примечания:

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

  • Значения, которым предшествует, : представляют параметры запросов, которые должны быть переданы из приложения

  • Оба user и group являются ключевыми словами языка, следовательно, плохой выбор имен объектов; Я изменил имена таблиц на users и groups .

Комментарии:

1. If group_name определяется как уникальный (но он должен!), Тогда insert ignore into groups он более прост и полезен (и не нуждается в WHERE).

2. @Akina: да, или on duplicate key … Но я пытался не записывать порядковые номера, так not exists что .