Какой будет мой SQL-оператор, чтобы вставить "Арнольд Шварценеггер" и "Hasta la vista baby" в эти две пустые SQL-таблицы?
Что бы я сказал, чтобы вставить "Арнольд Шварценеггер" и "Hasta la vista baby" в следующие пустые таблицы SQL?
Первоначально этот вопрос должен был звучать так: "Как вставить первые записи в таблицы SQL с двунаправленными ассоциациями и автоматически сгенерированным целым числом PK?" но я не был уверен, правильно ли я сформулировал это... В основном, у меня есть две таблицы Actors
а также CatchPhrases
,
Actors
похоже:
ActorId int NOT NULL PK (autogenerated by db)
FavoriteCatchPhraseId int NOT NULL FK
Name varchar(200) NOT NULL
CatchPhrases
похоже:
CatchPhraseId int NOT NULL PK (autogenerated by db)
ActorId int NOT NULL FK
PhraseText varchar(500) NOT NULL
Таким образом, актеры могут иметь несколько фраз, но должны иметь хотя бы одну. Уловочная фраза связана с актером. В настоящее время нет данных ни в одной таблице.
4 ответа
Я бы смоделировал это по-другому, чтобы избежать двунаправленного отношения (что было бы трудно сделать). Просто добавьте столбец (IsFavorite) в таблицу CatchPhrases. Либо используйте ограничение или бизнес-правило в коде, чтобы ограничить количество фраз-уловок, отмеченных как избранные для каждого актера, одним.
Актеры:
ActorId int NOT NULL PK (autogenerated by db)
Name varchar(200) NOT NULL
Схватывать фразы:
CatchPhraseId int NOT NULL PK (autogenerated by db)
ActorId int NOT NULL FK
PhraseText varchar(500) NOT NULL
IsFavorite bit NOT NULL
Убедитесь, что у вас есть индекс ActorId для таблицы CatchPhrases, чтобы вы могли быстро найти фразы-ловушки актера.
В качестве альтернативы можно использовать объединяющую таблицу, что позволит нескольким субъектам иметь одинаковую ключевую фразу
Актеры:
ActorId int NOT NULL PK (autogenerated by db)
Name varchar(200) NOT NULL
ActorCatchPhrases
ActorId int NOT NULL PK (FK to Actors)
CatchPhraseId int NOT NULL PK (FK to CatchPhrases)
IsFavorite bit NOT NULL
Схватывать фразы
PhraseId int NOT NULL PK (autogenerated by db)
PhraseText varchar(500) NOT NULL
Правило, а именно то, что родительская запись должна иметь хотя бы одну дочернюю запись, не может быть применено с декларативной ссылочной целостностью.
"Favorite" - это единственное число, и поэтому FavoriteCatchPhrase может быть просто атрибутом объекта Actor, то есть столбцом в таблице Actors. Вы можете хранить текст фразы. Но если вы хотите применить правило о том, что любимая фраза должна происходить из набора добросовестных фраз, фраз, которые были проверены и признаны действительно "броскими", а не просто не слишком запоминающимся высказыванием, тогда у вас будет таблица CatchPhrases, и вы можете иметь Actor.FavoriteCatchPhrase для сохранения идентификатора фразы и ссылочной таблицы CatchPhrases в качестве внешнего ключа, хотя несколько акторов могут использовать одну и ту же фразу-ловушку, если вы не добавите уникальный индекс в Actor.FavoriteCatchPhrase.
Я мог бы сделать это примерно так:
USE tempdb
;
CREATE TABLE
dbo.Actors
(
ActorId INTEGER IDENTITY PRIMARY KEY,
Name VARCHAR(200) NOT NULL UNIQUE
)
;
CREATE TABLE
dbo.CatchPhrases
(
CatchPhraseId INTEGER IDENTITY UNIQUE,
ActorId INTEGER NOT NULL REFERENCES dbo.Actors,
PhraseText VARCHAR(500) NOT NULL,
PRIMARY KEY (CatchPhraseId, ActorId)
)
;
CREATE TABLE
dbo.ActorFavouritePhrase
(
ActorId INTEGER NOT NULL REFERENCES dbo.Actors,
CatchPhraseId INTEGER NOT NULL,
FOREIGN KEY (CatchPhraseId, ActorId)
REFERENCES dbo.CatchPhrases (CatchPhraseId, ActorId),
PRIMARY KEY (ActorId, CatchPhraseId),
UNIQUE (CatchPhraseId, ActorId)
)
GO
CREATE INDEX [dbo.CatchPhrases ActorId]
ON dbo.CatchPhrases (ActorId)
GO
DECLARE @ActorId TABLE (Id INTEGER NOT NULL);
DECLARE @PhraseId TABLE (Id INTEGER NOT NULL)
;
BEGIN TRANSACTION
;
INSERT dbo.Actors
(Name)
OUTPUT inserted.ActorId
INTO @ActorId (Id)
VALUES ('Arnold Schwarzenegger')
;
DECLARE @AID INTEGER = (SELECT Id FROM @ActorId)
;
INSERT dbo.CatchPhrases
(ActorId, PhraseText)
OUTPUT inserted.CatchPhraseId
INTO @PhraseId (Id)
VALUES (@AID, 'Hasta la vista, baby')
;
DECLARE @PID INTEGER = (SELECT Id FROM @PhraseId)
;
INSERT dbo.ActorFavouritePhrase
(ActorId, CatchPhraseId)
VALUES (@AID, @PID)
;
COMMIT TRANSACTION
GO
DROP TABLE
dbo.ActorFavouritePhrase,
dbo.CatchPhrases,
dbo.Actors
;
Я думаю, что вы можете сделать это в транзакции, используя "грязное чтение" ( чтение незафиксировано).
Но это не очень приятно, даже если это возможно.
Как предложил @tvanfosson, самым чистым способом было бы отключить FK на столбце ActorId таблицы CatchPhrases.
Сначала создайте фиктивную строку CatchPhrases (для вставки идентификатора), например:
0 - 0 - "Нет любимой фразы", 0
Затем, когда вы хотите вставить строку Actors, по умолчанию используется:
(личность) - 0 - "Арнольд Шварценеггер"
Затем установите для переменной значение @@, которое сгенерирует вставка Actors
Тогда броская фраза:
(личность) - (переменная) - 'Hasta la vista baby'
Затем установите для переменной значение @@, которое будет сгенерировано вставкой CatchPhrases, и используйте ее для обновления идентификатора ключевой фразы в строке актеров.
... фу, ты уверен, что этот дизайн правильный?
РЕДАКТИРОВАТЬ
Хорошо, если мы можем изменить дизайн...
Смотря на отношения, у Актеров может быть много Фразовых фраз, и у Фишек может быть много Актеров. Таким образом, существует конструкция "многие ко многим", которая обычно подвергается рефакторингу с использованием объекта ссылки (MSDN называет это таблицей соединений):
Actors
|
-----
| | |
ActorsCatchphrases
| | |
-----
|
Catchphrases
- У актеров есть имя и детали актера (без ссылок на броские фразы)
- ActorsCatchphrases имеет ActorId и CatchphraseId и логическое значение того, является ли он фаворитом этого актера.
- Catchphrases содержит детали броской фразы (без ссылки на актера)