SQL Server에서 실제 일대일 관계를 만드는 방법
테이블이 두 개 있습니다.Country
그리고.Capital
나는 설정Capital
는 참하는외키기본키의를 키입니다Country
의 primarymodule 1.module을 합니다. Framework1입니다그러나 Entity Framework 데이터베이스를 먼저 사용할 때 모델은 1에서 0..1입니다.
SQL Server에서 일대일 관계를 만드는 방법은 무엇입니까?
SQL Server에서 True 1:1 관계를 유지하는 것은 기술적으로 불가능합니다. 이는 두 테이블 모두에 두 레코드를 동시에 삽입해야 한다는 것을 의미합니다(그렇지 않으면 삽입 시 제약 오류가 발생합니다). 두 테이블은 서로 외부 키 관계입니다.
즉, 외부 키로 설명된 데이터베이스 설계는 1대 0..1 관계입니다.테이블 B의 레코드를 요구할 수 있는 제약 조건은 없습니다.테이블 B에 레코드를 생성하는 트리거와 유사 관계를 가질 수 있습니다.
그래서 몇 가지 유사한 해결책이 있습니다.
먼저 모든 데이터를 단일 테이블에 저장합니다.그러면 EF에 문제가 없을 것입니다.
또는 두 번째로, 엔티티는 관련 레코드가 없는 한 삽입을 허용하지 않을 정도로 똑똑해야 합니다.
세 번째로, 가장 가능성이 높은 문제는 해결하려는 실제 문제(XY 문제) 대신 솔루션이 작동하지 않는 이유를 묻는 것입니다.
갱신하다
1대 1 관계가 어떻게 작동하지 않는지 현실에서 설명하기 위해, 저는 닭의 비유나 계란 딜레마를 사용할 것입니다.저는 이 딜레마를 해결할 의도는 없지만, 만약 여러분이 계란 테이블에 계란을 추가하기 위해서는 닭의 관계가 존재해야 하고, 닭이 테이블에 있어야 한다는 제약이 있다면, 여러분은 계란 테이블에 계란을 추가할 수 없습니다.그 반대도 사실입니다.달걀 표에 존재하는 달걀과 달걀과의 관계가 모두 없으면 닭을 닭 표에 추가할 수 없습니다.따라서 규칙/제약 조건 중 하나를 위반하지 않고 데이터베이스에서 모든 레코드를 만들 수 없습니다.
일대일 관계의 데이터베이스 명명법은 오해의 소지가 있습니다.제가 본 모든 관계(따라서 제 경험)는 일대일 관계(0대 1 또는 1)로 더 서술적일 것입니다.
업데이트 EF 5.0 - 일대일 지원
SQL Server는 종속 행이 null일 수 있도록 허용합니다.이제 Entity Framework Core 5.0을 사용하여 필요에 따라 종속 속성을 구성할 수 있습니다.EF 5 새로운 기능
발췌:
EF Core 5.0에서는 소유한 엔티티에 대한 탐색을 필수 종속 항목으로 구성할 수 있습니다.예:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>(b =>
{
b.OwnsOne(e => e.HomeAddress,
b =>
{
b.Property(e => e.City).IsRequired();
b.Property(e => e.Postcode).IsRequired();
});
b.Navigation(e => e.HomeAddress).IsRequired();
});
}
외부 키를 기본 키로 설정한 다음 두 기본 키 필드에서 관계를 설정합니다.바로 그거야!관계 선의 양쪽 끝에 키 기호가 표시됩니다.이것은 1 대 1을 나타냅니다.
일대일 관계를 가진 SQL Server 데이터베이스 설계 확인
이 작업은 간단한 기본 외부 키 관계를 만들고 외부 키 열을 다음과 같은 방법으로 고유하게 설정하여 수행할 수 있습니다.
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]);
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);
모든 것이 정상인지 확인합니다.
SELECT * FROM [Employee];
SELECT * FROM [Salary];
관계 to Many)에서는번일 적 으 대 1 외 에 다 (1 수 관 있 수 습 다 입 할 력 번 여 러 계 는 서 로 대 1 대 ▁multiple ▁now 있 니 다 one ▁primary ▁enter ▁times 습 ), ▁could ▁you 에 ▁relations 이 ▁in ▁(EmployeeID
할 것입니다.
INSERT INTO [Salary] (
[EmployeeID]
, [SalaryAmount]
)
VALUES
(1, 3000);
위의 문장은 다음과 같이 오류를 표시합니다.
유니크 키 제약 조건 'UQ__Salary__7 위반AD04FF0C044141D' 개체 'dbo'에 중복 키를 삽입할 수 없습니다.급여'.중복 키 값은 (1)입니다.
트리거, 계산된 열, 추가 테이블 또는 기타 '이국적인' 트릭(외부 키 및 고유 제약 조건만)을 사용하지 않고도 하나의 작은 경고로 엄격하게* 일대일 관계를 달성하는 방법을 알고 있습니다.
저는 제가 주의할 점을 설명하는 것을 돕기 위해 인정된 답변에서 닭과 달걀의 개념을 차용할 것입니다.
(어쨌든 현재 DB에서는) 닭이나 달걀이 먼저여야 한다는 것은 사실입니다.다행히도 이 솔루션은 정치적이지 않고 어떤 것이 우선되어야 하는지 규정하지 않습니다. 이는 구현자에게 맡겨집니다.
주의할 점은 기술적으로 레코드가 '우선'되도록 허용하는 테이블은 다른 테이블의 해당 레코드 없이 생성된 레코드를 가질 수 있지만, 이 솔루션에서는 이러한 레코드 하나만 허용됩니다.레코드가 하나만 생성된 경우(닭 또는 달걀만 생성된 경우) '외로운' 레코드가 삭제되거나 다른 테이블에 일치하는 레코드가 생성될 때까지 두 테이블 중 하나에 더 이상 레코드를 추가할 수 없습니다.
솔루션:
각 테이블에 외부 키를 추가하고 다른 키를 참조하며 각 외부 키에 고유한 제약 조건을 추가한 다음 하나의 외부 키를 null로 만들고 다른 하나는 null로 만들지 않으며 기본 키도 null로 만듭니다.이 작업이 수행되려면 null 가능 열의 고유 제약 조건이 하나의 null만 허용해야 합니다(SQL Server의 경우에는 해당되지만 다른 데이터베이스는 해당되지 않습니다).
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
삽입하려면 먼저 달걀을 삽입해야 합니다(닭고기의 경우 null).이제 닭 한 마리만 삽입할 수 있고 닭은 '미청구' 알을 참조해야 합니다.마지막으로, 추가된 계란은 업데이트될 수 있으며 '청구되지 않은' 닭을 참조해야 합니다.어떤 경우에도 두 마리의 닭이 같은 알을 참조하도록 만들 수 없거나 그 반대의 경우도 마찬가지입니다.
삭제하려면 동일한 논리를 따를 수 있습니다. 계란의 치킨을 null로 업데이트하고, 새로 '청구되지 않은' 치킨을 삭제하고, 계란을 삭제합니다.
또한 이 솔루션을 사용하면 쉽게 스왑할 수 있습니다.흥미롭게도, 스와핑은 잠재적인 실용성을 가지고 있기 때문에 그러한 솔루션을 사용하는 가장 강력한 주장일 수 있습니다.일반적으로, 대부분의 경우, 두 테이블의 일대일 관계는 단순히 두 테이블을 하나로 리팩터링함으로써 더 잘 구현됩니다. 그러나 잠재적인 시나리오에서 두 테이블은 엄격한 일대일 관계를 요구하지만 '파트너'를 자주 교환하거나 일반적으로 다시 정렬해야 하는 진정으로 구별되는 엔티티를 나타낼 수 있습니다.재임용 후에도 여전히 일대일 관계를 유지하고 있습니다.더 일반적인 솔루션을 사용하는 경우 외부 키 열 하나만 다시 정렬하면 되는 이 솔루션과 달리 엔티티 중 하나의 모든 데이터 열을 다시 정렬하는 모든 쌍에 대해 업데이트/덮어쓰기해야 합니다.
글쎄요, 이것이 표준 제약 조건을 사용하여 제가 할 수 있는 최선입니다(판단하지 마세요). 아마도 누군가가 그것을 유용하게 여길 것입니다.
SQL Server에서 일대일 관계를 만드는 방법은 무엇입니까?
단답:그럴수는 없어요.
긴 답변:만약 당신이 감히 계속 읽어본다면, 당신은 할 수 있습니다.
DBMS에서 연기 가능한 제약 조건이 지원되지 않는 경우 1:1 관계를 "구현"하기 위한 두 가지 주요 접근 방식이 있다는 것을 알고 있습니다(*cough* MS SQL Server *cough*).이 게시물에서는 이러한 두 가지 주요 접근 방식에 대해 설명합니다.
두은 모두 EF를 하게 함으로써 있습니다.VIEW
TABLE
, 당신은 "EF", "EF", "EF"가 하지 않을입니다.VIEW
객체, 그러나 여전히 편리한 쿼리 및 제품 유형 보기의 신속한 쿼리에 유용합니다.1:1
엔티티가 별도의 테이블에 있습니다.
이 두 가지 접근 방식 모두 다른 테이블을 사용하여 구축됩니다.ValidCountries
). PK 값만 포함하며 다음 두 가지 이유로 존재합니다.
- 의 FK 은 FK 제약 조건입니다.
1:1
테이블 수1:1
too 블도이테:!:의 행. 그래서 행이 안에 있습니다.ValidCountries
필요한 모든 관련 데이터가 해당 테이블에 존재하지 않는 한 존재할 수 없습니다. - 수신 대상을 지정합니다.
FOREIGN KEY
다른 엔티티의 제약 조건.이에 대한 자세한 설명은 아래에 설명되어 있습니다.
두 가지 접근 방식은 다음과 같은 제약 조건에서 다릅니다.1:1
테이블,, 성원테테블블, 이원성구.TRIGGER
개체 및 EF와의 호환성.이 두 가지 접근 방식은 데이터 모델링 방법과 비즈니스 요구사항에 따라 달라질 수 있습니다.
방법 이두가지접모않사습다니지용하두법근않다▁neither니aches▁use▁of습을 사용하지 않습니다.CHECK CONSTRAINT
으로, UDF를 하는 주요 입니다.1:1
제약이 있지만 이러한 접근 방식은 성능에 대한 평판이 좋지 않습니다.
접근법 1: 두 개를 더 사용합니다. TABLE
는 순방향 변환용, 증명용) 및 객하(읽기/쓰기 , 쓰기증체용읽및기명하는변환정향방나는나른validitydeclar쓰▁objects하, 다는하명)증기용▁(/객읽)VIEW
하는 것1:1
a로부터의 데이터JOIN
:
이 접근 방식은 세 번째 테이블을 사용하여 (공유된) PK 값만 "포워드-선언"하는 반면, 다음을 원하는 다른 테이블은
1:1
서로의 관계는 순방향 변환 테이블만 참조합니다.또 다른 "최종"
TABLE
(FK 제약 조건을 통해) 지정된 PK에 대해 유효함이 확실히 존재함을 증명하는 데 사용됩니다.그런 다음 이 복잡성은 (기술적으로 선택 가능한) 뒤에 숨겨져 있습니다.
VIEW
를INNER JOIN
테이블 중 3개그 이상)를 하는 경우.INSERT/UPDATE/DELETE/MERGE
DML 작업.- Entity Framework에서는 EF가 다음과 같이 가장하는 것이 완벽하게 행복하기 때문에 이 기능은 매우 유용합니다.
VIEW
입니다.TABLE
주의할 점은 이러한 모든 접근 방식이 우리의 의지에 따라 현명한 EF보다 우선하기 때문입니다(따라서 마이그레이션을 사용하지 않도록 설정하십시오!). - "최종" 테이블은 다음과 같이 불필요해 보일 수 있습니다.
VIEW
잘못된 데이터가 노출되지 않습니다. 실제로 다른 개별 엔터티 테이블에서 들어오는 외부 키 참조의 대상 역할을 하는 것이 매우 필요합니다(순방향 참조 테이블을 절대 참조해서는 안 됨).
- Entity Framework에서는 EF가 다음과 같이 가장하는 것이 완벽하게 행복하기 때문에 이 기능은 매우 유용합니다.
세 개의 테이블은 다음과 같습니다.
- 표 1: PK 값만 포함된 "전진 선언 테이블"
- 에서 (의 예에의서의의 ())
Countries
그리고.Capitals
), 이것은 다음과 같은 이름의 테이블일 것입니다.CountryDeclarations
(또는)CountryDecl
약식) 및 스토어 전용CountryName
- 값, 이, 공, 입 에 대해 된 PK입니다.Countries
그리고.Capitals
표).
- 표 2: 전방 선언 테이블에 대한 FK가 있는 하나 이상의 종속 테이블.
- OP의 예에서 이것은 두 개의 테이블입니다.
TABLE Countries
와 함께CountryName
테이블의 PK와 해당 FK를 전진 선언 테이블에만 할당합니다.TABLE Capitals
와 함께CountryName
테이블의 PK와 해당 FK를 전진 선언 테이블에만 할당합니다.
- OP의 예에서 이것은 두 개의 테이블입니다.
- 표 3: 공개적으로 볼 수 있는 주 테이블로, 순방향 선언 테이블과 모든 종속 테이블에 대한 FK가 있습니다.
- 예에이다같습니다과음의것은입니다.
TABLE ValidCountries
+ to PK + FKCountryDecl
따로로따.FK
에서 의까지.Countries
그리고.Capitals
.
다음은 이 접근 방식의 데이터베이스 다이어그램입니다.
에서 를 조회할 때
Countries
및/는Capitals
,이 항상 .INNER JOIN
와 함께ValidCountries
그러면 항상 유효한 데이터를 쿼리한다는 확실한 보장을 받을 수 있습니다.- 아니면 그냥 그것을 사용하세요.
VIEW
을 얻기 위해JOIN
당신을 위해 이미 완성되었습니다.
- 아니면 그냥 그것을 사용하세요.
▁the라는 것을 기억하세요.
1:1
구성 요소 간의 관계가 적용되지 않습니다.Countries
그리고.Capitals
합니다. 그렇지 대 입니다. 그렇지 않으면 닭 대 달걀 문제가 있을 것입니다.INSERT
.- 은 항상▁though▁always당▁if은신▁you'll면.
INSERT
안으로Countries
앞에Capitals
)DELETE
할 수 .FK
로터의 의 제약Capitals
京都까지Countries
하지만 이것은 실제로 어떤 이점도 추가하지 않습니다. 왜냐하면Countries
테이블은 해당하는 것을 보장할 수 없습니다.Capitals
행이 존재합니다.
- 은 항상▁though▁always당▁if은신▁you'll면.
은 이디인다호다니됩환음과은과 호환됩니다.
IDENTITY
PK도 마찬가지입니다. 포워드 선언 테이블만 다음을 가집니다.IDENTITY
열, 다른 모든 테이블은 정규 분포를 갖습니다.int
PK+FK 열입니다.
이 접근 방식의 SQL은 다음과 같습니다.
CREATE SCHEMA app1; /* The `app1` schema contains the individual objects to avoid namespace pollution in `dbo`. */
GO
CREATE TABLE app1.CountryDecl (
CountryName nvarchar(100) NOT NULL,
CONSTRAINT PK_CountryDecl PRIMARY KEY ( CountryName )
);
GO
CREATE TABLE app1.Countries (
CountryName nvarchar(100) NOT NULL,
CapitalName nvarchar(255) NOT NULL,
Inhabitants bigint NOT NULL,
AreaKM2 bigint NOT NULL,
CONSTRAINT PK_Countries PRIMARY KEY ( CountryName ),
CONSTRAINT FK_CountriesDecl FOREIGN KEY ( CountryName ) REFERENCES app1.CountryDecl ( CountryName ),
-- CONSTRAINT FK_Countries_Capitals FOREIGN KEY ( CountryName ) REFERENCES app1.Capitals ( CountryName ) -- This FK is entirely optional and adds no value, imo.
);
GO
CREATE TABLE app1.Capitals (
CountryName nvarchar(100) NOT NULL,
CapitalName nvarchar(255) NOT NULL,
Inhabitants bigint NOT NULL,
AreaKM2 int NOT NULL,
CONSTRAINT PK_Capitals PRIMARY KEY ( CountryName ),
CONSTRAINT FK_CountriesDecl FOREIGN KEY ( CountryName ) REFERENCES app1.CountryDecl ( CountryName )
);
GO
CREATE TABLE app1.ValidCountries (
CountryName nvarchar(100) NOT NULL,
CONSTRAINT PK_ValidCountries PRIMARY KEY ( CountryName ),
CONSTRAINT FK_ValidCountries_to_Capitals FOREIGN KEY ( CountryName ) REFERENCES app1.Capitals ( CountryName ),
CONSTRAINT FK_ValidCountries_to_Countries FOREIGN KEY ( CountryName ) REFERENCES app1.Countries ( CountryName ).
CONSTRAINT FK_ValidCountries_to_Decl FOREIGN KEY( CountryName ) REFERENCES app1.CountriesDecl ( CountryName )
);
GO
CREATE VIEW dbo.Countries AS
SELECT
-- ValidCountries:
v.CountryName,
-- Countries
cun.Inhabitants AS CountryInhabitants,
cun.Area AS CountryArea,
-- Capitals
cap.Capital AS CapitalCityName,
cap.CityArea AS CapitalCityArea,
cap.CityInhabitants AS CapitalCityInhabitants
FROM
app1.ValidCountries AS v
INNER JOIN app1.Countries AS cun ON v.CountryName = cun.CountryName
INNER JOIN app1.Capitals AS cap ON v.CountryName = cap.CountryName;
GO
CREATE TRIGGER Countries_Insert ON dbo.Countries
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO app1.CountriesDecl (
CountryName
)
SELECT
CountryName
FROM
inserted;
-------
INSERT INTO app1.Capitals (
CountryName,
Capital,
CityInhabitants,
CityArea
)
SELECT
CountryName,
CapitalCityName,
CapitalCityInhabitants,
CapitalCityArea
FROM
inserted;
-------
INSERT INTO app1.Countries (
CountryName,
Capital,
Inhabitants,
Area
)
SELECT
CountryName,
CapitalCityName,
CountryInhabitants,
CountryArea
FROM
inserted;
----
INSERT INTO app1.ValidCountries (
CountryName
)
SELECT
CountryName
FROM
inserted;
-------
END;
/* NOTE: Defining UPDATE and DELETE triggers for the VIEW is an exercise for the reader. */
- Entity Framework 및 Entity Framework Core를 사용할 때 이러한 접근 방식은 궁극적으로 Entity Framework를 능가하는 것에 관한 것이므로 EF가 마이그레이션을 수행하거나 DDL을 생성 및 실행하지 않도록 하는 것이 중요합니다.
CREATE TABLE
클래스를 으로 하는 문...) Code-First 명령어를 사용합니다.EF no-first는 "데이터베이스 우선" 모델을 지원하지만, https://github.com/sjh37/EntityFramework-Reverse-POCO-Code-First-Generator 과 같은 코드 우선 코드젠과 함께 "데이터베이스에서 코드 우선"을 사용할 수 있습니다.
방식을 나 코드 ▁for▁▁cont▁if▁modelgen▁using-▁scaffold▁oning▁default▁code▁separateaining▁up에 대한 별도의 엔티티가 포함된 모델이 될 것입니다.
app1.Countries
,app1.Capitals
,app1.CountriesDecl
그리고.app1.ValidCountries
따라서 EF 모델에서 원하지 않는 개체를 필터링하도록 코드젠을 구성해야 합니다.- 이 경우, 저는 모든 것을 제외할 것입니다.
app1.*
EF의에게 EF , 신를료지치다시니를 처리하도록 합니다.VIEW dbo.Countries
하나의 실체로서 (수학적으로 모든 것과 마찬가지로 말이 됩니다.1:1
두 엔티티 간의 관계는 다른 두 엔티티의 제품 유형으로 정의된 단일 엔티티와 동일합니다. - 냐하면.
VIEW
를 가지고 있지 않습니다.PRIMARY KEY
아무 것도 아닌FOREIGN KEY
제약 조건, EF(기본값)는 엔티티 클래스를 에서 올바르게 코드화할 수 없습니다.VIEW
그러나 앞에서 언급한 코드젠 도구는 EF를 올바른 방법으로 쉽게 찌를 수 있게 합니다(다음을 참조하십시오).ViewProcessing
및 방법, 그고AddForeignKeys
아래의 방법).
- 이 경우, 저는 모든 것을 제외할 것입니다.
만약 당신이 그것을 유지한다면.
app1.Countries
그리고.app1.Capitals
EF의 가 EF를 하십시오.INSERT
당신의 코드가 처음에 하지 않는 한 그 두 테이블에 실패할 것입니다.INSERT
안으로app1.CountriesDecl
.또는 추가할 수 있습니다.
CREATE TRIGGER Countries/Capitals_Insert ON app1.Countries/app1.Capitals INSTEAD OF INSERT
그이수것다니입될행것▁the▁which▁perform다▁will그IF NOT EXIST ... INSERT INTO app1.CountriesDecl
.는 EF와 관련된 것입니다.
UPDATE
그리고.DELETE
적어도 그 두 테이블에서.
의 추가 만 2: 하나의 추가 사항: 하나의 추가 사항입니다.TABLE
대만, 지하반FK
은 열입니다.NULL
-및 -능및 -가▁- -및능VIEW
잘못된/불완전한 행을 숨기기 위한 커튼으로 사용됩니다.
접근법 1이 "객체는 항상 불변해야 한다"는 사고방식에서 아이디어를 차용한 것으로 요약될 수 있다면 접근법 2는 언어에서 영감을 받아 기존 개체를 내부에서 변형할 수 있으므로 컴파일러가 각 변환 단계가 개체의 유효 유형을 변경하여 일부 유형 제약 조건을 충족하는지 확인할 수 있습니다.
예를 들어, 이 유사 유형 스크립트를 생각해 보십시오(2022년 현재, TypeScript는 POJsO에 속성을 추가할 때 여전히 지원/탐지를 하지 않는 것으로 보이기 때문에 (따라서 구조 유형을 확장하는) 유효하고 변수의 정적 유형을 확장할 수 있습니다).
interface MyResult { readonly name: string; readonly year: number; }; function doSomething() : MyResult { let result = {}; // return result; // Error: Cannot return `result` yet: it doesn't conform to `MyResult` (there's no `name` nor `year` value) result.name = "NameGoesHere"; // So let's define `name`. // return result; // ERROR: Still cannot return `result` yet: it still doesn't yet have a `year` property. result.year = 2022; // So let's add `year`. return result; // No error, `result` can now be returned OK because it conforms to `interface MyResult`. }
염두에 두고, 우리는 염두면두에을, 리는우를 가질 수 .
TABLE
불완전한 /완전한물을Country
그리고.Capital
롭게 삽입할 수FOREIGN KEY
조건은 제약조입니다.NULL
-able, 참십시오하조를아래.- 테이블 이름이 지정됩니다.
dbo.CountriesData
그리고.dbo.CapitalsData
에dbo.Countries
그리고.dbo.Capitals
각각 테이블에 유효하고 올바른 엔티티가 아닌 임의의 "데이터"만 포함되어 있음을 나타냅니다.이것은 제 개인적인 명명 규칙입니다.YMMV. - 접근법 1과 마찬가지로,
VIEW dbo.Countries
유효한 엔티티만 단일 제품 유형으로 표시하는 존재합니다.- 으로 선으로추정수있다니습도를 정의할 수도 있습니다.
VIEW
"EF"를 를 더 많이 ).INSERT
각 뷰에 대해 개별적으로 작업).
- 으로 선으로추정수있다니습도를 정의할 수도 있습니다.
- 테이블 이름이 지정됩니다.
하지만 접근법 1과는 달리,
dbo.CapitalsData
이제 테이블에는 OP의 특정 데이터베이스 설계 목표의 결과인 복합 기본 키가 있습니다. 이는 데이터베이스에 적용되지 않을 수 있습니다.- 는 PK를 허용하기 합니다.
dbo.Countries
NULL
CountryName
가치는 없지만 가치는 있습니다.FK_CountriesData_to_Capitals
제약이 가해진.이것은 필요합니다 왜냐하면CountryName
기도합니의 .dbo.CountriesData
그럴 리가 없습니다.NULL
이는 SQL Server가 FK의 모든 열이 FK가 아닌 경우에만 FK 제약 조건을 적용하기 때문에 작동합니다.NULL
PK 설계가 다른 경우에는 이 설계가 다릅니다.
- 는 PK를 허용하기 합니다.
CREATE TABLE dbo.CountriesData (
CountryName nvarchar(100) NOT NULL,
CapitalName nvarchar(255) NULL,
Inhabitants bigint NOT NULL,
Area geography NOT NULL,
CONSTRAINT PK_CountriesData PRIMARY KEY ( CountryName ),
CONSTRAINT FK_CountriesData_to_Capitals FOREIGN KEY ( CountryName, CapitalName ) REFERENCES dbo.CapitalsData ( CapitalName )
);
CREATE TABLE dbo.CapitalsData (
CountryName nvarchar(100) NOT NULL,
CapitalName nvarchar(255) NOT NULL,
Inhabitants bigint NOT NULL,
Area geography NOT NULL,
CONSTRAINT PK_CapitalsData PRIMARY KEY ( CountryName, CountryName ),
CONSTRAINT FK_CapitalssData_to_Countries FOREIGN KEY ( CapitalName ) REFERENCES dbo.CountriesData ( CountryName )
);
CREATE VIEW dbo.Countries AS
SELECT
-- Countries
cun.Inhabitants AS CountryInhabitants,
cun.Area AS CountryArea,
-- Capitals
cap.Capital AS CapitalCityName,
cap.CityArea AS CapitalCityArea,
cap.CityInhabitants AS CapitalCityInhabitants
FROM
dbo.CountriesData AS cd
INNER JOIN dbo.CapitalsData AS cad ON cd.CountryName = cad.CountryName;
CREATE TABLE dbo.ValidCountries (
-- This TABLE is largely the as in Approach 1. Ensure that all incoming FKs only reference this table and not dbo.CountriesData or dbo.CapitalsData.
-- NOTE: When using EF, provided to trick EF into treating `VIEW dbo.Countries` as a TABLE then you don't need to include this table in your EF model at all (just be sure to massage all of EF's FK relationships from other entities that initially point to `ValidCountries` to point to the `VIEW dbo.Countries` entity instead.
CountryName nvarchar(100) NOT NULL,
CapitalName nvarchar(255) NOT NULL,
CONSTRAINT PK_ValidCountries PRIMARY KEY ( CountryName ),
CONSTRAINT FK_ValidCountries_to_Capitals FOREIGN KEY ( CountryName ) REFERENCES dbo.CapitalsData ( CountryName, CapitalName ),
CONSTRAINT FK_ValidCountries_to_Countries FOREIGN KEY ( CountryName ) REFERENCES dbo.CountriesData ( CountryName )
);
CREATE TRIGGER After_UPDATE_in_CountriesData_then_INSERT_into_ValidCountries_if_valid ON dbo.CountriesData
AFTER UPDATE
AS
BEGIN
INSERT INTO dbo.ValidCountries ( CountryName, CapitalName )
SELECT
i.CountryName,
i.CapitalName
FROM
inserted.CountryName AS i
INNER JOIN dbo.CapitalsData AS capd ON -- The JOINs prevents inserting CountryNames for countries that are either invalid or already exist in dbo.ValidCountries.
capd.CountryName = i.CountryName
AND
capd.CapitalName = i.CapitalName
LEFT OUTER JOIN dbo.ValidCountries AS v ON -- This is a "LEFT ANTI JOIN" due to the WHERE condition below.
v.CountryName = i.CountryName
WHERE
v.CountryName IS NULL
AND
i.CapitalName IS NOT NULL;
END;
CREATE TRIGGER After_INSERT_in_CapitalsData_then_SET_C ON dbo.CapitalsData
AFTER INSERT
AS
BEGIN
-- Due to the specific design of dbo.CapitalsData, any INSERT will necessarily complete a valid product-type entity, so we can UPDATE dbo.CountriesData to set CapitalName to the correct value.
UPDATE
cd
SET
cd.CapitalName = inserted.CapitalName
FROM
dbo.CountriesData AS cd
INNER JOIN inserted AS i ON
cd.CountryName = i.CountryName
AND
cd.CapitalName IS NULL
WHERE
i.CountryName IS NOT NULL;
END;
- 수동 DML의 경우:
- .
INSERT
새로운 나라...- 첫째번▁first
INSERT INTO dbo.CountriesData
에 처에는으로NULL
CapitalName
value.value.value.
- 는 SQL 값복합 FK에서 의 값이 SQL Server일 때 FK 조건을 하기 때문에 .
NULL
.
- 그리고나서
INSERT INTO dbo.CapitalsData
그 됨)CountryName
반대로 입니다.NULL
). - 에만 를 합니다.
UPDATE dbo.CountriesData SET CapitalName = inserted.CapitalName WHERE CountryName = inserted.CountryName
. - 어디에 당신의
VIEW dbo.Countries
이제는 지금의 사람들을 폭로할 것입니다.1:1
-관련자료.
- 첫째번▁first
DELETE
첫 번째 작업은역수즉합야, 행해니다로으먼저순)으로 수행해야 .UPDATE
FK 제거위해기그, 러면하를.DELETE
각 테이블에서, 임의의 순서로).UPDATE
작업은 특별한 취급이 필요하지 않습니다.
- .
- 나는 당신이 실제로 위의 모든 것을 옮길 수 있다는 것에 주목합니다.
INSERT
로의 논리.AFTER INSERT
양쪽 모두에 대한 트리거CountriesData
그리고.CapitalsData
테이블, 이 의미는 다음과 같습니다.- ㅠㅠ
UPDATE
▁an▁into의.AFTER INSERT
에 방아쇠를 당기다.dbo.CapitalsData
의 경우) - (으)ㄹ 수 있는 것처럼 (으)ㄹ 수 없는 것처럼 (으)는WHERE inserted.CountryName IS NOT NULL
할 코드는 두 개의 SQL 만 수행하면 됩니다.INSERT
과 두 중AFTER INSERT
자동으로 에만 데이터를 자동으로 처리합니다. 는 트거는나머데데처최이리종가다터로있수니습볼에서에 됩니다.VIEW dbo.Countries
. - 이 접근 방식은 EF에서 더 잘 작동합니다. EF를 가지고 장난칠 필요가 없기 때문입니다.
CountriesDecl
으로 하기, 개인수행블.INSERT
에 대한 작전.dbo.CountriesData
그리고.dbo.CapitalsData
실패하지는 않을 것이다 - 하지만 그것은 없다는 것을 기억하라.1:1
두 테이블/테이블 사이의 관계
- ㅠㅠ
SQL에서 1 대 1 관계는 두 테이블의 필드를 하나로 병합함으로써 만들어집니다!
테이블을 1대 1의 관계를 가진 두 엔티티로 나눌 수 있다는 것을 알고 있습니다.대부분의 경우 "테이블에 있는 이진 데이터의 무거운 필드"에 게으른 로드를 사용하기 때문에 이 기능을 사용합니다.
예:이름 열(문자열), 일부 메타데이터 열, 축소판 그림 열 및 그림 자체의 이진수(최대)가 포함된 그림이 있는 테이블이 있습니다.프로그램에서 먼저 수집 컨트롤에 이름과 축소판 그림만 표시하고 필요한 경우에만 "전체 그림 데이터"를 로드합니다.
그것이 당신이 찾고 있는 것이라면.그것은 "테이블 분할" 또는 "수평 분할"이라고 불리는 것입니다.
https://visualstudiomagazine.com/articles/2014/09/01/splitting-tables.aspx
이렇게 하는 가장 쉬운 방법은 NULL이 아닌 표 A 및 B 필드를 모두 사용하여 표 1개만 만드는 것입니다.이런 식으로 다른 것 없이 하나를 갖는 것은 불가능합니다.
이건 어때요?
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)
)
언급URL : https://stackoverflow.com/questions/10292355/how-to-create-a-real-one-to-one-relationship-in-sql-server
'programing' 카테고리의 다른 글
고유한 레코드 값 가져오기 (0) | 2023.07.04 |
---|---|
스프링 보안이 설정된 스프링 부트: 'securityFilterChainRegistration' 이름의 빈을 생성하는 중 오류 발생 (0) | 2023.07.04 |
.springBeans 파일은 무엇입니까? (0) | 2023.07.04 |
Adonis 컨트롤러를 사용하여 만들어진 경로에서 Vue 구성 요소에서 axios 요청을 만들려면 어떻게 합니까? (0) | 2023.07.04 |
반복적인 비동기 요청 시간 초과Spring Boot 관리 로그에서 예외 발생 (0) | 2023.07.04 |