Вставка строк в таблицу, которая связана с другой таблицей

В моей схеме базы данных у меня есть идентифицированный объект. Идентификатор можно использовать повторно, и, таким образом, с сущностью существует отношение «один ко многим». Пример: У человека может быть прозвище. Псевдонимы не уникальны и могут использоваться многими людьми. Таким образом, схема может выглядеть так:

PERSON
id
name
nickname_id

NICKNAME
id
name

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

Я мог бы оптимизировать большие вставки, сначала запросив Nickname для всех псевдонимов. Язык запросов JPA:

SELECT n FROM NICKNAME n WHERE name in ('Krusty', 'Doppy', 'Flash', etc)

А затем создайте новые псевдонимы по мере необходимости, а затем установите для людей псевдонимы.

Это немного усложняет программу, так как она должна временно хранить никнеймы в памяти. Кроме того, некоторые базы данных имеют ограничение на параметры предложения IN (SQL Server 2100 или около того), поэтому я выполняю несколько запросов.

Мне интересно, как этот вопрос решается другими. В частности, когда база данных нормализована и объект имеет связь с другим объектом, вставка нового объекта в основном приводит к необходимости проверки другого объекта. Для больших вставок это может быть медленным, если только операция не поднята в область кода. Есть ли способ автоматически вставлять связанные строки таблицы?

К вашему сведению, я использую реализацию JPA в Hibernate.


person Steve Kuo    schedule 08.12.2008    source источник
comment
'n' в SELECT n FROM неверен; Вы, вероятно, имеете в виду id.   -  person Jonathan Leffler    schedule 08.12.2008


Ответы (4)


Я не уверен, что ORM справится с этим, но в прямом SQL вы могли бы:

  1. Создайте таблицу пар имя/псевдоним,
  2. INSERT INTO NicknameTable SELECT Nickname FROM temp WHERE Nickname NOT IN (SELECT Nickname FROM NicknameTable)
  3. Вставьте в основную таблицу, зная, что псевдоним существует.

В вашем примере вы можете просто иметь столбец псевдонимов NULL без другой таблицы, если только у человека не может быть более одного псевдонима.

person dkretz    schedule 08.12.2008
comment
Это, безусловно, то, как я бы справился с этим, за исключением того, что я бы использовал левое соединение вместо оператора not in, поскольку они, как правило, работают лучше (по крайней мере, в SQL Server). - person HLGEM; 08.12.2008

Правдиво? Я бы сделал псевдоним столбцом varchar в таблице Person и забыл о таблице псевдонимов. Никнейм — это атрибут человека, а не отдельная сущность.

Является ли это упрощенным примером, и ваши «идентификаторы» действительно делают выгоду от отношений сущности?

редактировать: Хорошо, понял, что это всего лишь искусственный пример. Вопрос хороший, потому что он возникает достаточно часто.

Стандартный SQL поддерживает форму оператора INSERT с необязательным предложением «...ON DUPLICATE KEY UPDATE...». Поддержка этого синтаксиса зависит от марки базы данных. Если вы добавите ограничение UNIQUE к имени идентификатора в таблице псевдонимов, повторяющаяся запись вызовет часть UPDATE предложения (вы можете выполнить фиктивное обновление вместо того, чтобы что-либо менять).

CREATE TABLE Nickname (
  id SERIAL PRIMARY KEY,
  name VARCHAR(20) UNIQUE
);

INSERT INTO Nickname (name) VALUES ("Bill")
  ON DUPLICATE KEY UPDATE name = name;
person Bill Karwin    schedule 08.12.2008
comment
Моя схема человек-никнейм была просто примером. Мой вопрос заключается в том, как вставить большое количество данных, которые связаны с другим объектом (таблицей). - person Steve Kuo; 08.12.2008

INSERT INTO Person(Name, NicknameID)
    VALUES(:name, (SELECT id FROM Nickname WHERE Name = :nickname))

Если INSERT завершается ошибкой из-за того, что псевдоним не существует, вставьте псевдоним, а затем запись о человеке.

Я предполагаю, что :name и :nickname идентифицируют переменные хоста, содержащие имя и псевдоним пользователя, а столбцу that person.id будет автоматически присвоено значение, если оно будет исключено из SQL. Адаптируйтесь к вашим обстоятельствам.

Если вы считаете, что большинство псевдонимов на самом деле будут уникальными, вы можете просто попытаться безоговорочно вставить псевдоним, но проигнорировать ошибку, которая возникает, если псевдоним уже существует.

person Jonathan Leffler    schedule 08.12.2008

В качестве альтернативы, возможно, может помочь оператор «MERGE»? Он предлагает возможность вставки нового значения или обновления существующего значения. Синтаксис и поддержка зависят от БД, но, возможно, более распространены, чем опция ON DUPLICATE.

person andora    schedule 02.09.2009