2つのテーブルがCountry
ありCapital
、Capital
の主キーを、の主キーを参照する外部キーとして設定しCountry
ます。しかし、Entity Frameworkデータベースを最初に使用すると、モデルは1から0..1になります。
SQL Serverで1対1の関係を作成するにはどうすればよいですか?
2つのテーブルがCountry
ありCapital
、Capital
の主キーを、の主キーを参照する外部キーとして設定しCountry
ます。しかし、Entity Frameworkデータベースを最初に使用すると、モデルは1から0..1になります。
SQL Serverで1対1の関係を作成するにはどうすればよいですか?
SQL ServerでTrue1対1の関係を持つことは技術的に不可能であると確信しています。これは、両方のレコードを同時に挿入する必要があることを意味します(そうしないと、挿入時に制約エラーが発生します)。両方のテーブル。両方のテーブルは相互に外部キー関係にあります。
そうは言っても、外部キーで記述されたデータベース設計は1対0..1の関係です。tableBのレコードを必要とするような制約はありません。tableBにレコードを作成するトリガーとの疑似関係を持つことができます。
したがって、いくつかの疑似ソリューションがあります
まず、すべてのデータを1つのテーブルに保存します。そうすれば、EFで問題は発生しません。
または次に、エンティティは、関連付けられたレコードがない限り、挿入を許可しないように十分にスマートである必要があります。
または、第3に、おそらく、解決しようとしている問題があり、解決しようとしている実際の問題(XY問題)ではなく、解決策が機能しない理由を尋ねています。
アップデート
1対1の関係がどのように機能しないかを現実で説明するために、鶏が先か卵が先かというジレンマのアナロジーを使用します。私はこのジレンマを解決するつもりはありませんが、卵を卵テーブルに追加するために、鶏の関係が存在し、鶏がテーブルに存在する必要があるという制約がある場合は、 EggテーブルにEggを追加できませんでした。逆もまた真です。EggとEggテーブルに存在するEggの両方との関係がなければ、ChickenテーブルにChickenを追加することはできません。したがって、ルール/制約の1つに違反することなく、データベース内ですべてのレコードを作成することはできません。
1対1の関係のデータベースの命名法は誤解を招く恐れがあります。私が見たすべての関係(したがって私の経験)は、1対(0または1)の関係としてより説明的です。
外部キーを主キーとして設定してから、両方の主キーフィールドに関係を設定します。それでおしまい!リレーションシップラインの両端にキーサインが表示されます。これは1対1を表します。
これを確認してください:1対1の関係を持つSQLServerデータベース設計
これを行うには、次の方法で、単純な主外部キー関係を作成し、外部キー列を一意に設定します。
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];
現在、一般的に一対多の関係(1対多)では、複数回入力できますがEmployeeID
、ここではエラーがスローされます
INSERT INTO [Salary] (
[EmployeeID]
, [SalaryAmount]
)
VALUES
(1, 3000);
上記のステートメントは、次のようにエラーを表示します
UNIQUEKEY制約の違反'UQ__Salary__7AD04FF0C044141D'。オブジェクト'dbo.Salary'に重複するキーを挿入できません。重複するキー値は(1)です。
トリガー、計算列、追加のテーブル、またはその他の「エキゾチック」なトリック(外部キーと一意の制約のみ)を使用せずに、厳密に*1対1の関係を実現する方法を1つ知っています。
警告を説明するために、受け入れられた回答から鶏と卵の概念を借ります。
鶏か卵のどちらかが最初に来なければならないのは事実です(とにかく現在のDBでは)。幸いなことに、このソリューションは政治的になることはなく、どちらを先に実行する必要があるかを規定していません。実装者に任されています。
注意点は、レコードを「最初に」技術的に許可するテーブルでは、他のテーブルに対応するレコードがなくてもレコードを作成できることです。ただし、このソリューションでは、そのようなレコードは1つだけ許可されます。1つのレコードのみ(鶏が先か卵が先か)が作成された場合、「孤独な」レコードが削除されるか、他のテーブルに一致するレコードが作成されるまで、2つのテーブルのいずれにもレコードを追加できません。
解決:
各テーブルに外部キーを追加し、他のテーブルを参照し、各外部キーに一意の制約を追加して、一方の外部キーをnull許容にし、もう一方をnull不可にし、主キーも作成します。これが機能するためには、null許容列に対する一意の制約で1つの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を使用)。現在、挿入できるのは鶏肉のみであり、「未請求」の卵を参照する必要があります。最後に、追加された卵は更新でき、「未請求」の鶏肉を参照する必要があります。同じ卵を参照するように2羽の鶏を作ることはできません。その逆も同様です。
削除するには、同じロジックに従うことができます。卵のチキンをnullに更新し、新しく「要求されていない」チキンを削除し、卵を削除します。
このソリューションでは、簡単に交換することもできます。興味深いことに、スワッピングは実用的な可能性があるため、このようなソリューションを使用するための最も強力な議論になる可能性があります。通常、ほとんどの場合、2つのテーブルの1対1の関係は、2つのテーブルを1つにリファクタリングするだけでより適切に実装されます。ただし、潜在的なシナリオでは、2つのテーブルは、厳密な1対1の関係を必要とするが、1対1を維持しながら、頻繁に「パートナー」を交換するか、一般的に再配置する必要がある、真に異なるエンティティを表す場合があります。 -再配置後の1つの関係。より一般的なソリューションを使用した場合、このソリューションとは対照的に、エンティティの1つのすべてのデータ列を更新/上書きして、すべてのペアを再配置する必要があります。
まあ、これは私が標準的な制約を使ってできる最善のことです(判断しないでください:)多分誰かがそれが役に立つと思うでしょう。
SQLの1対1の関係は、両方のテーブルのフィールドを1つにマージすることによって作成されます。
テーブルを1対1の関係で2つのエンティティに分割できることを知っています。「テーブル内のバイナリデータの重いフィールド」で遅延読み込みを使用するため、ほとんどの場合、これを使用します。
例:名前列(文字列)、メタデータ列、サムネイル列、および画像自体のvarbinary(max)を持つ画像を含むテーブルがあります。アプリケーションでは、コレクションコントロールに名前とサムネイルのみを最初に表示してから、必要な場合にのみ「全体像データ」をロードします。
それがあなたが探しているものなら。これは「テーブル分割」または「水平分割」と呼ばれるものです。
https://visualstudiomagazine.com/articles/2014/09/01/splitting-tables.aspx
SQL Serverで1対1の関係を作成するにはどうすればよいですか?
簡単な答え:できません。
長い答え:あなたが読むことを敢えてするならば、あなたはそうすることができます...
延期可能な制約がDBMSでサポートされていない場合に1:1の関係を「実装」するには、主に2つのアプローチがあることを理解しています(* cough * MS SQL Server * cough *)。この投稿では、これら2つの主要なアプローチについて説明します。
これらのアプローチは両方とも、EFをだましてaVIEW
をとして扱うことにより、EFとある程度の互換性がありTABLE
ます。EFを使用していない場合は、おそらくVIEW
オブジェクトは必要ありませんが、便利なクエリや、別のテーブルにあるエンティティの製品タイプビューをすばやくクエリする場合に便利です。1:1
これらのアプローチは両方とも、 PK値のみを含む別のテーブル(ValidCountries
)を使用して構築されており、次の2つの理由で存在します。
1:1
メンバーテーブルにFK制約を設定する(3つ以上のテーブルも設定できることを忘れないでください)。したがって、必要なすべての関連データがそれぞれのテーブルに存在しない限り1:1
、の行は存在ValidCountries
できません。FOREIGN KEY
からの着信制約のターゲットを提供するため。これについては、以下で詳しく説明し、説明します。1:1
2つのアプローチは、メンバーテーブルに対する制約、TRIGGER
オブジェクトの使用、およびEFとの互換性が異なります。これらの2つのアプローチには、さらに多くのバリエーションが可能であると確信しています。これは、データのモデル化方法とビジネス要件によって異なります。
これらのアプローチはどちらも、CHECK CONSTRAINT
UDFでルールを使用して他のテーブルのデータを検証しません。これは現在、1:1
制約を実装するための主な方法ですが、そのアプローチのパフォーマンスに対する評判は低くなっています。
TABLE
オブジェクト(1つは前方宣言用、もう1つは有効性の証明として)を使用し、読み取り/書き込みを使用して、 :からの有効なデータVIEW
のみを公開します。1:1
JOIN
このアプローチでは、3番目のテーブルを使用して(共有)PK値のみを「前方宣言」しますが、1:1
相互の関係が必要な他のテーブルは、前方宣言テーブルのみを参照します。
別の「最終」TABLE
は、任意のPKに対して、有効なものが確実に存在することを(FK制約を介して)証明するために使用されます。
この複雑さは、 DML操作もサポートしながら、有効なデータのみを公開し、3つ(またはそれ以上)のバッキングテーブルの1つを実行する(技術的にオプションの)VIEW
オブジェクトの背後に隠されています。INNER JOIN
INSERT/UPDATE/DELETE/MERGE
VIEW
EFは、aがであると偽って完全に満足しているため、これはEntityFrameworkでうまく機能TABLE
します。注意点は、これらすべてのアプローチは厳密にデータベースファーストであるということです。これらのアプローチはすべて、 EFを巧みに操り、私たちの意志に合わせて曲げるためです(したがって、移行を無効にしてください!)VIEW
、実際には、他の個別のエンティティテーブル(前方宣言テーブルを参照してはならない)からの受信外部キー参照のターゲットとして機能する必要があります。 。
VIEW
オブジェクト(インデックス付きビューでさえ)がRDBMS外部キー制約に参加できないためです。これは煩わしいことです。3つのテーブルは次のとおりです。
Countries
とCapitals
)では、これはlike CountryDeclarations
(またはCountryDecl
略して)という名前のテーブルであり、値のみ を格納します。これは、とテーブルCountryName
の両方の共有PKです)。Countries
Capitals
TABLE Countries
CountryName
テーブルのPKとそのFKを前方宣言テーブルのみに使用します。TABLE Capitals
CountryName
テーブルのPKとそのFKを前方宣言テーブルのみに使用します。TABLE ValidCountries
PK + FKを使用し、列をとCountryDecl
に分離します。FK
Countries
Capitals
このアプローチのデータベース図は次のとおりです。
Countries
および/またはテーブルからデータをクエリする場合、常にCapitals
提供されている場合は、常に有効なデータをクエリしていることが保証されます。INNER JOIN
ValidCountries
VIEW
て、JOIN
すでに完了しているものを取得します。構成要素とテーブルの間の1:1
関係は強制されないことに注意してください。これは必要です。そうしないと、で鶏と卵の問題が発生します。Countries
Capitals
INSERT
INSERT
入ると確信している場合は、直接からに制約を追加できますが、テーブルは対応する行が存在することを保証できないため、これは実際には何の利点も追加しません。Countries
Capitals
DELETE
FK
Capitals
Countries
Countries
Capitals
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. */
CREATE TABLE
.. 。)Code-Firstエンティティモデルクラスに基づくステートメント。
EFは「データベースファースト」モデルをサポートしなくなりましたが、https://github.com/sjh37/EntityFramework-Reverse-POCO-Code-のようなコードファーストコード生成で「データベースからのコードファースト」を使用できます。 First-Generator(免責事項:これは私の個人的なお気に入りのコード生成者であり、私はそのプロジェクトに貢献しています)。
このアプローチを使用してデータベースでデフォルトのscaffoldまたはcode-first-codegenを実行すると、、、および-の個別のエンティティを含むモデルapp1.Countries
になりapp1.Capitals
ます。したがって、code-genを構成して、それらのオブジェクトを除外する必要があります。 EFモデルには必要ありません。app1.CountriesDecl
app1.ValidCountries
app1.*
EFからすべてのテーブルを除外し、代わりにEFにVIEW dbo.Countries
単一のエンティティとして扱うように指示します(数学的には、2つのエンティティ間のすべて の関係は、それらの製品タイプとして定義された単一のエンティティ1:1
と同じものであるため、意味があります)他の2つのエンティティ)。VIEW
は制約も制約PRIMARY KEY
もないFOREIGN KEY
ため、EF(デフォルト)はからエンティティクラスを正しくVIEW
コード生成できませんが、前述のコード生成ツールを使用すると、EFを正しい方法で簡単に微調整できます(メソッドと以下のViewProcessing
メソッドを探してください)。AddForeignKeys
それ)。EFでエンティティタイプとしてとテーブルを保持する場合は、コードが最初にintoを実行しない限り、EFにこれら2つのテーブルに対してinを実行させると失敗することに注意してください。app1.Countries
app1.Capitals
INSERT
INSERT
app1.CountriesDecl
またはCREATE TRIGGER Countries/Capitals_Insert ON app1.Countries/app1.Capitals INSTEAD OF INSERT
、を実行するを追加することもできますIF NOT EXIST ... INSERT INTO app1.CountriesDecl
。
ただし、EFは、少なくともこれら2つのテーブルでUPDATE
問題は発生しません。DELETE
TABLE
のオブジェクトは1つだけですが、FK
列はNULL
-able-であり、aVIEW
は無効/不完全な行を隠すためのカーテンとして使用されます。アプローチ1を「オブジェクトは常に不変でなければならない」という考え方からの借用として要約できる場合、アプローチ2は、コンパイラがそれぞれを検証できるように、既存のオブジェクトをインプレースで変更できる言語に触発されています。ミューテーションステップは、オブジェクトの有効なタイプを変更して、あるタイプの制約を満たすようにします。
たとえば、この疑似TypeScriptについて考えてみます(2022年の時点で、POJsOにプロパティを追加する(したがって構造型を拡張する)ことが有効であり、変数の静的型を拡張する場合、TypeScriptはまだサポート/検出されていないようです)。
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
ます。以下を参照してください。
dbo.CountriesData
およびdbo.CapitalsData
の代わりに名前が付けられています。これは私の個人的な命名規則です。YMMV。dbo.Countries
dbo.Capitals
VIEW dbo.Countries
として公開する存在が存在します。
VIEW
行うには、より多くの作業を行う必要があります)。INSERT
ただし、アプローチ1とは異なり、dbo.CapitalsData
テーブルには複合主キーが含まれるようになりました。これは、OPの特定のデータベース設計目標の結果であり、データベースには適用されない場合があります。
dbo.Countries
に非値を持つことができるようにするために必要です。のPKでもあるため、これが必要です。したがって、することはできません。これが機能するのは、SQLServerがFKのすべての列が非である場合にのみFK制約を適用するためです。PKデザインが異なる場合、これはあなたにとって異なります。NULL
CountryName
FK_CountriesData_to_Capitals
CountryName
dbo.CountriesData
NULL
NULL
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;
INSERT
...
INSERT INTO dbo.CountriesData
に初期NULL
CapitalName
値を使用します。NULL
。INSERT INTO dbo.CapitalsData
(またはその逆、逆に提供されCountryName
ますNULL
)。UPDATE dbo.CountriesData SET CapitalName = inserted.CapitalName WHERE CountryName = inserted.CountryName
。VIEW dbo.Countries
を公開します。1:1
DELETE
操作は逆の順序で実行する必要があります(つまり、最初UPDATE
にFKをクリアし、次にDELETE
各テーブルから任意の順序で)。UPDATE
操作には特別な処理は必要ありません。INSERT
上記のすべてのロジックを、テーブルとテーブルのAFTER INSERT
両方のトリガーに実際に移動できることに注意してください。これは、次のことを意味します。
CountriesData
CapitalsData
UPDATE
をAFTER INSERT
トリガーにdbo.CapitalsData
!(およびその逆)-ただし、必ずチェックを追加してくださいWHERE inserted.CountryName IS NOT NULL
-ただし、これを行うと、クライアントのSQLコードは2つINSERT
のステートメントを実行するだけで済み、2つのAFTER INSERT
トリガーの1つが残りを自動的に処理しますが、データが最終的に有効になります-すると、に表示されVIEW dbo.Countries
ます。CountriesDecl
テーブルをいじくり回す必要がないため、個々の操作を実行INSERT
しても失敗することはdbo.CountriesData
ありdbo.CapitalsData
ませんが1:1
、これら2つのテーブル/エンティティ間には関係がないことに注意してください。これを実現する最も簡単な方法は、テーブルAとテーブルBの両方のフィールドがNULLでないテーブルを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)
)