Вставка строк в таблицу, которая связана с другой таблицей - PullRequest
1 голос
/ 08 декабря 2008

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

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)

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

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

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

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

Ответы [ 4 ]

1 голос
/ 08 декабря 2008

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

  1. Создать таблицу пар имя / псевдоним,
  2. INSERT INTO NicknameTable ВЫБРАТЬ псевдоним ОТ ТЕМА, ГДЕ Псевдоним NOT IN (ВЫБЕРИТЕ псевдоним ИЗ NicknameTable)
  3. Вставить в основную таблицу, зная, что псевдоним существует.

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

0 голосов
/ 02 сентября 2009

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

0 голосов
/ 08 декабря 2008
INSERT INTO Person(Name, NicknameID)
    VALUES(:name, (SELECT id FROM Nickname WHERE Name = :nickname))

Если выполнить ВСТАВКУ не удалось из-за того, что псевдоним не существует, введите псевдоним, а затем запись о человеке.

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

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

0 голосов
/ 08 декабря 2008

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

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

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

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

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

INSERT INTO Nickname (name) VALUES ("Bill")
  ON DUPLICATE KEY UPDATE name = name;
...