Jak stworzyć prawdziwą relację jeden do jednego w SQL Server

Mam dwie tabele tableA i tableB, ustawiłem klucz podstawowy tableB jako klucz obcy, który odwołuje się do klucza podstawowego tableA. Ale kiedy używam bazy danych Entity Framework-najpierw, model jest 1 do 0..1.

Jak stworzyć relację jeden do jednego w SQL Server?

Author: ΩmegaMan, 2012-04-24

8 answers

Jestem prawie pewien, że technicznie niemożliwe jest, aby w SQL Server miała prawdziwą relację 1 do 1, ponieważ oznaczałoby to, że będziesz musiał wstawiać oba rekordy w tym samym czasie (w przeciwnym razie pojawi się błąd ograniczenia na insert), w obu tabelach, przy czym obie tabele mają relację z kluczem obcym.

Biorąc to pod uwagę, Twój projekt bazy danych opisany za pomocą klucza obcego to 1 do 0..1 Związek. Nie ma możliwości ograniczenia, które wymagałoby rekordu w tableB. Możesz mieć pseudo-relację z wyzwalaczem, który tworzy rekord w tableB.

Więc jest kilka pseudo-rozwiązań

Najpierw zapisz wszystkie dane w jednej tabeli. Wtedy nie będziesz miał problemów w EF.

Lub po drugie, Twoja jednostka musi być wystarczająco inteligentna, aby nie zezwalać na wstawkę, chyba że ma powiązany rekord.

Lub po trzecie, i najprawdopodobniej, masz problem, który próbujesz rozwiązać, i pytasz nas, dlaczego Twoje rozwiązanie nie działa zamiast rzeczywisty problem, który próbujesz rozwiązać (Problem XY) .

UPDATE

Aby wyjaśnić w rzeczywistość jak relacje 1 do 1 nie działają, użyję analogii dylematu kura lub jajko. Nie zamierzam rozwiązywać tego dylematu, ale jeśli miałbyś mieć ograniczenie, które mówi, że aby dodać jajko do stołu jaj, związek kury musi istnieć, a kura musi istnieć w stole, to nie mógłbyś dodać jajka do jajka stolik. Jest też odwrotnie. Nie można dodać kurczaka do stołu z kurczakiem bez zarówno związku z jajem, jak i jajkiem istniejącym w stole z jajami. W ten sposób nie można tworzyć żadnych rekordów w bazie danych bez łamania jednej z reguł/ograniczeń.

Baza danych nomenklatura relacji jeden do jednego jest myląca. Wszystkie relacje, które widziałem (nie-bo moje doświadczenie) byłoby bardziej opisowe jako jeden-do - (zero lub jeden) relacje.

 67
Author: Erik Philips,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-01 18:08:10

Ustaw klucz obcy jako klucz podstawowy, a następnie Ustaw relację na obu polach klucza podstawowego. To jest to! Powinieneś zobaczyć znak klucza na obu końcach linii relacji. To oznacza jeden do jednego.

Tutaj wpisz opis obrazka

Sprawdź to: Projekt bazy danych SQL Server z relacją jeden do jednego

 73
Author: Pranay Rana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-24 05:56:59

Można to zrobić, tworząc prostą podstawową relację klucza obcego i ustawiając kolumnę klucza obcego na unique w następujący sposób:

CREATE TABLE [Employee] (
    [ID]    INT PRIMARY KEY
,   [Name]  VARCHAR(50)
);

CREATE TABLE [Salary] (
    [EmployeeID]    INT UNIQUE NOT NULL
,   [SalaryAmount]  INT 
);

ALTER TABLE [Salary]
ADD CONSTRAINT FK_Salary_Employee FOREIGN KEY([EmployeeID]) 
    REFERENCES [Employee]([ID]);

Schemat

INSERT INTO [Employee] (
    [ID]
,   [Name]
)
VALUES
    (1, 'Ram')
,   (2, 'Rahim')
,   (3, 'Pankaj')
,   (4, 'Mohan');

INSERT INTO [Salary] (
    [EmployeeID]
,   [SalaryAmount]
)
VALUES
    (1, 2000)
,   (2, 3000)
,   (3, 2500)
,   (4, 3000);

Sprawdź, czy wszystko jest w porządku

SELECT * FROM [Employee];
SELECT * FROM [Salary];

Obecnie w podstawowym obcym związku (jeden do wielu), można wprowadzić wiele razy EmployeeID, ale tutaj błąd zostanie wyrzucony

INSERT INTO [Salary] (
    [EmployeeID]
,   [SalaryAmount]
)
VALUES
    (1, 3000);

Powyższa instrukcja wyświetli błąd jako

Naruszenie unikalnego ograniczenia klucza "UQ__pensja _ _ 7AD04FF0C044141D". Nie można wstawić zduplikowanego klucza w obiekcie ' dbo.Wynagrodzenie". Zduplikowaną wartością klucza jest (1).

 37
Author: ashim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-20 23:17:59

Jest jeden sposób, w jaki wiem, jak osiągnąć ścisłą* relację jeden do jednego bez użycia wyzwalaczy, kolumn obliczeniowych, dodatkowych tabel lub innych "egzotycznych" sztuczek( tylko klucze obce i unikalne ograniczenia), z jednym małym zastrzeżeniem.

Pożyczę koncepcję kurczaka i jajka z zaakceptowanej odpowiedzi, aby pomóc mi wyjaśnić zastrzeżenie.

Faktem jest, że albo kura, albo jajko muszą być pierwsze(w obecnym DBs tak czy inaczej). Na szczęście rozwiązanie to nie ma charakteru politycznego i nie nie przepisać, który ma być pierwszy-pozostawia to do wykonawcy.

Zastrzeżenie jest takie, że tabela, która pozwala rekordowi "być pierwszym" technicznie może mieć rekord utworzony bez odpowiedniego rekordu w drugiej tabeli; jednak w tym rozwiązaniu dozwolony jest tylko jeden taki rekord. Gdy zostanie utworzony tylko jeden rekord (tylko kura lub jajko), nie można dodać więcej rekordów do żadnej z dwóch tabel, dopóki rekord "samotny" nie zostanie usunięty lub nie zostanie utworzony pasujący rekord w inny stół.

Rozwiązanie:

Dodaj klucze obce do każdej tabeli, odwołując się do drugiej, dodaj unikalne ograniczenia do każdego klucza obcego i ustaw jeden klucz obcy jako nullable, drugi nie jako nullable, a także klucz podstawowy. Aby to zadziałało, unikalna ograniczenie w kolumnie nullable musi zezwalać tylko na jedno null (tak jest w SQL Server, nie jest pewne co do innych baz danych).

CREATE TABLE dbo.Egg (
    ID int identity(1,1) not null,
    Chicken int null,
    CONSTRAINT [PK_Egg] PRIMARY KEY CLUSTERED ([ID] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE dbo.Chicken (
    Egg int not null,
    CONSTRAINT [PK_Chicken] PRIMARY KEY CLUSTERED ([Egg] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE dbo.Egg  WITH NOCHECK ADD  CONSTRAINT [FK_Egg_Chicken] FOREIGN KEY([Chicken]) REFERENCES [dbo].[Chicken] ([Egg])
GO
ALTER TABLE dbo.Chicken  WITH NOCHECK ADD  CONSTRAINT [FK_Chicken_Egg] FOREIGN KEY([Egg]) REFERENCES [dbo].[Egg] ([ID])
GO
ALTER TABLE dbo.Egg WITH NOCHECK ADD CONSTRAINT [UQ_Egg_Chicken] UNIQUE([Chicken])
GO
ALTER TABLE dbo.Chicken WITH NOCHECK ADD CONSTRAINT [UQ_Chicken_Egg] UNIQUE([Egg])
GO

Aby wstawić, najpierw należy wstawić jajko (z null dla kurczaka). Teraz Można włożyć tylko kurczaka i musi odnosić się do "nieodebranego" jaja. Wreszcie dodane jajko może zostać zaktualizowane i musi odnosić się do "nieodebranego" kurczaka. W żadnym momencie nie można zmusić dwóch kurcząt do odniesienia się do tego samego jaja lub odwrotnie.

Aby usunąć, można postępować zgodnie z tą samą logiką: zaktualizować kurczaka egg 'a do null, usunąć świeżo "nieodebranego" kurczaka, usunąć jajko.

To rozwiązanie pozwala również na łatwą wymianę. Co ciekawe, zamiana może być najsilniejszym argumentem za zastosowaniem takiego rozwiązania, ponieważ ma potencjalne praktyczne zastosowanie. Zwykle w większości przypadków relacja jeden do jednego dwóch tabel jest lepiej zaimplementowana przez zwykłe refaktoryzację dwóch tabel w jedną; jednak w potencjalnym scenariuszu dwie tabele mogą reprezentować naprawdę odrębne podmioty, które wymagają ścisłej relacji jeden do jednego, ale muszą często wymieniać się "partnerami" lub być ponownie ułożone w ogóle, przy jednoczesnym utrzymaniu relacji jeden do jednego po ponownym ułożeniu. Jeśli zastosowano bardziej powszechne rozwiązanie, wszystkie kolumny danych jeden z elementów musiałby być zaktualizowany/nadpisany dla wszystkich par, które są ponownie ułożone, w przeciwieństwie do tego rozwiązania, gdzie tylko jedna kolumna kluczy obcych musi być ponownie ułożona (nullable foreign key column).

Cóż, to jest najlepsze co mogłem zrobić używając standardowych ograniczeń (nie oceniaj:) może komuś się to przyda.

 4
Author: tomosius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-14 07:17:44

Relacje 1 do 1 w SQL są tworzone przez połączenie pola obu tabel w jeden !

Wiem, że można podzielić tabelę na dwie jednostki z relacją 1 do 1. Najczęściej używasz tego, ponieważ chcesz korzystać z leniwego ładowania na "ciężkim polu danych binarnych w tabeli".

Exemple: masz tabelę zawierającą zdjęcia z kolumną z nazwą (string), może jakąś kolumną metadanych, kolumną miniatury i samym obrazem varbinary (max). W swojej aplikacji na pewno wyświetli najpierw tylko nazwa i miniaturka w kontrolce kolekcji, a następnie załaduj "Pełne Dane obrazu" tylko w razie potrzeby.

Jeśli to jest to, czego szukasz. Jest to coś, co nazywa się "podział tabeli" lub "podział poziomy".

Https://visualstudiomagazine.com/articles/2014/09/01/splitting-tables.aspx

 1
Author: Marco Guignard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-28 10:23:45

Najprostszym sposobem na osiągnięcie tego celu jest utworzenie tylko 1 tabeli z polami tabeli a i B bez NULL. W ten sposób nie można mieć jednego bez drugiego.

 0
Author: Jonathan Nappee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-05 13:52:04

A co z tym ?

create table dbo.[Address]
(
Id int identity not null,
City nvarchar(255) not null,
Street nvarchar(255) not null,
CONSTRAINT PK_Address PRIMARY KEY (Id)
)

create table dbo.[Person]
(
Id int identity not null,
AddressId int not null,
FirstName nvarchar(255) not null,
LastName nvarchar(255) not null,
CONSTRAINT PK_Person PRIMARY KEY (Id),
CONSTRAINT FK_Person_Address FOREIGN KEY (AddressId) REFERENCES dbo.[Address] (Id)
)
 0
Author: Muflix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-18 21:04:33

Relacja 1 do 1 jest bardzo możliwa. Nawet jeśli diagram relacji nie pokazuje bezpośrednio relacji 1 do 1. Jeśli zaimplementujesz go jak poniżej, będzie działał jako relacja jeden do jednego.

Użyję podstawowego przykładu, aby wyjaśnić koncepcję, w której jedna osoba może mieć tylko jeden paszport. Ten przykład doskonale sprawdza się w MS Access. Dla wersji SQL Server wykonaj ten link .

Pamiętaj, że w MS Access skrypty SQL mogą być uruchamiane tylko w czas, a nie jak wyświetlane tutaj w kolejności.

CREATE TABLE Person
(
Pk_Person_Id INT PRIMARY KEY,
Name VARCHAR(255),
EmailId VARCHAR(255),
);

CREATE TABLE PassportDetails
(
Pk_Passport_Id INT PRIMARY KEY,
Passport_Number VARCHAR(255),
Fk_Person_Id INT NOT NULL UNIQUE, 
FOREIGN KEY(Fk_Person_Id) REFERENCES Person(Pk_Person_Id)
);
 -2
Author: Cacious7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-21 16:37:21