72

我有两个表CountryCapital我将Capital的主键设置为引用主键的外键Country。但是当我首先使用实体​​框架数据库时,模型是 1 到 0..1。

如何在 SQL Server 中创建一对一关系?

在此处输入图像描述

4

8 回答 8

85

我很确定在 SQL Server 中建立真正的 1 对 1 关系在技术上是不可能的,因为这意味着你必须同时插入两条记录(否则你会在插入时遇到约束错误),在两个表,两个表之间都有外键关系。

话虽如此,使用外键描述的数据库设计是 1 到 0..1 的关系。没有可能需要 tableB 中的记录的约束。您可以与在 tableB 中创建记录的触发器建立伪关系。

所以有一些伪解决方案

首先,将所有数据存储在一个表中。那么你在EF中就没有问题了。

或者其次,您的实体必须足够聪明,除非它具有关联的记录,否则不允许插入。

或者第三,最有可能的是,你有一个你试图解决的问题,你问我们为什么你的解决方案不起作用,而不是你试图解决的实际问题(一个 XY 问题)

更新

为了在现实中解释1 对 1 关系如何不起作用,我将使用鸡或蛋困境的类比。我不打算解决这个困境,但是如果你有一个约束,说为了向 Egg 表中添加一个 Egg,Chicken 的关系必须存在,并且 Chicken 必须存在于表中,那么你不能在 Egg 表中添加一个 Egg。反之亦然。如果没有与 Egg 的关系以及 Egg 表中存在的 Egg,则无法将 Chicken 添加到 Chicken 表。因此,在不破坏规则/约束之一的情况下,不能在数据库中创建每条记录。

一对一关系的数据库命名具有误导性。我见过的所有关系(因此我的经验)将更具描述性作为一对(零或一)关系。

于 2012-04-24T05:56:46.780 回答
80

将外键设置为主键,然后在两个主键字段上设置关系。而已!您应该在关系线的两端看到一个关键标志。这代表一对一。

在此处输入图像描述

检查这一点:具有一对一关系的 SQL Server 数据库设计

于 2012-04-24T05:56:59.807 回答
48

这可以通过创建一个简单的主外键关系并以下列方式将外键列设置为唯一来完成:

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];

现在一般在Primary Foreign Relations(一对多)中,可以多次输入EmployeeID,但是这里会报错

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

上面的语句将显示错误为

违反 UNIQUE KEY 约束“UQ__Salary__7AD04FF0C044141D”。无法在对象“dbo.Salary”中插入重复键。重复键值为 (1)。

于 2015-07-14T10:55:29.613 回答
5

有一种方法我知道如何在不使用触发器、计算列、附加表或其他“奇异”技巧(只有外键和唯一约束)的情况下实现严格的*一对一关系,但有一点需要注意。

我将从公认的答案中借用鸡和蛋的概念来帮助我解释警告。

事实上,必须先有鸡或先有蛋(无论如何在当前的数据库中)。幸运的是,这个解决方案没有政治化,也没有规定哪个必须先出现 - 它由实施者决定。

需要注意的是,从技术上讲,允许记录“先行”的表可以创建一个记录,而另一个表中没有相应的记录;然而,在这个解决方案中,只允许一个这样的记录。当仅创建一条记录(仅创建 chicken 或 egg)时,在删除“lonely”记录或在另一个表中创建匹配记录之前,不能将更多记录添加到两个表中的任何一个。

解决方案:

将外键添加到每个表,引用另一个,为每个外键添加唯一约束,并使一个外键可以为空,另一个不能为空并且也是主键。为此,可空列上的唯一约束必须只允许一个空值(在 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

要插入,首先必须插入一个鸡蛋(鸡为空)。现在,只能插入一只鸡,并且它必须引用“无人认领”的鸡蛋。最后,可以更新添加的鸡蛋,它必须引用“无人认领”的鸡。在任何时候都不能让两只鸡引用同一个鸡蛋,反之亦然。

要删除,可以遵循相同的逻辑:将egg's Chicken 更新为null,删除新“无人认领”的鸡,删除egg。

该解决方案还允许轻松交换。有趣的是,交换可能是使用这种解决方案的最有力论据,因为它具有潜在的实际用途。通常,在大多数情况下,只需将两张表重构为一张,就能更好地实现两张表的一对一关系;但是,在潜在的情况下,这两个表可能代表真正不同的实体,它们需要严格的一对一关系,但需要经常交换“合作伙伴”或重新排列,同时仍保持一对一-重新安排后的一段关系。如果使用更常见的解决方案,则必须更新/覆盖其中一个实体的所有数据列,以便重新排列所有对,与此解决方案相反,

好吧,这是我使用标准约束所能做的最好的事情(不要评判:) 也许有人会发现它很有用。

于 2016-07-14T06:11:32.293 回答
2

SQL中的1对1关系是通过将两个表的字段合并为一个来建立的!

我知道您可以将表拆分为具有 1 对 1 关系的两个实体。大多数时候你使用它是因为你想在“表中二进制数据的重字段”上使用延迟加载。

示例:您有一个包含图片的表格,其中包含名称列(字符串)、可能是一些元数据列、缩略图列和图片本身 varbinary(max)。在您的应用程序中,您肯定会首先在集合控件中仅显示名称和缩略图,然后仅在需要时才加载“完整图片数据”。

如果这是您正在寻找的。这就是所谓的“表拆分”或“水平拆分”。

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

于 2016-11-28T10:23:45.197 回答
2

如何在 SQL Server 中创建一对一关系?

简短的回答:你不能。

长答案:你可以,如果你敢继续阅读......


我知道当 DBMS ( *cough* MS SQL Server *cough* )不支持可延迟约束时,有两种主要方法可以“实现”1:1 关系。这篇文章讨论了这两种主要方法。

这两种方法都通过欺骗 EF 将 aVIEW视为 a与 EF 具有一定程度的兼容性TABLE。如果您不使用 EF,那么您可能不需要这些VIEW对象,但它们对于方便查询和快速查询单独表中实体的产品类型视图仍然很方便。1:1

这两种方法都是围绕使用另一个ValidCountries包含PK 值的表 ( ) 构建的,存在两个原因:

  1. 对两个1:1成员表都有 FK 约束(不要忘记您也可以有三个或更多表!):因此,除非所有必需的相关数据都存在于各自的表中,否则1:1ValidCountries 不能存在。
  2. 为来自其他实体的任何传入FOREIGN KEY约束提供目标。这将在下面更详细地解释和演示。

1:1这两种方法的不同之处在于它们对成员表的约束、它们对TRIGGER对象的使用以及它们与 EF 的兼容性。我确信这两种方法的更多变化是可能的 - 这实际上取决于您如何建模数据和您的业务需求。

这些方法都没有使用CHECK CONSTRAINT带有 UDF 的规则来验证其他表中的数据,这是目前实现1:1约束的主要方法,但这种方法在性能方面的声誉很差。


方法 1:使用另外两个 TABLE对象(一个用于前向声明,另一个作为有效性证明)和一个读/写VIEW来仅公开1:1来自 a 的有效数据JOIN

  • 此方法使用第三个表“前向声明” (共享)PK 值,而其他希望1:1彼此建立关系的表引用前向声明表。

  • 另一个“final”TABLE用于证明(通过 FK 约束)对于任何给定的 PK,valid肯定存在。

  • 然后,这种复杂性隐藏在一个(技术上可选的)VIEW对象后面,该对象只公开有效数据并执行INNER JOIN3 个(或更多)后备表中的一个,同时还支持INSERT/UPDATE/DELETE/MERGEDML 操作。

    • 这适用于实体框架,因为 EF 非常乐意假装 aVIEWTABLE. 需要注意的是,所有这些方法都是严格的数据库优先的,因为所有这些方法都比 EF 更聪明,可以让其屈服于我们的意愿(所以一定要禁用迁移!)
    • 虽然“最终”表可能看起来是多余的,因为VIEW它永远不会暴露无效数据,但实际上非常有必要作为来自其他单独实体表(绝不能引用前向声明表)的传入外键引用的目标.
  • 这三个表是:

    1. 表 1 :只有PK 值的“前向声明表” 。
    • 在 OP 的示例中(ofCountriesCapitals),这将是一个名为 like CountryDeclarations(或CountryDecl简称)的表,并且 CountryName存储值,这是 theCountriesCapitals表的共享 PK)。
    1. 表 2:一个(或多个!)从属表,其 FK 指向前向声明表。
      • 在 OP 的示例中,这将是 2 个表:
        • TABLE CountriesCountryName作为表的 PK及其FK 仅对前向声明表。
        • TABLE CapitalsCountryName作为表的 PK及其FK 仅对前向声明表。
    2. 表 3:公开可见的表,它对前向声明表和所有从属表具有 FK。
    • 在 OP 的示例中,这将TABLE ValidCountries使用 PK + FK to并将列与和CountryDecl分开。FKCountriesCapitals

这是这种方法的数据库图:

在此处输入图像描述

  • Countries和/或Capitals表中查询数据时,只要您始终提供INNER JOINValidCountries您就会得到硬保证,即您始终在查询有效数据。

    • 或者只是使用VIEWJOIN为您完成已经完成的工作。
  • 请记住,成分表和表之间1:1的关系不是强制的:这是必要的,否则会出现鸡与蛋的问题。CountriesCapitalsINSERT

    • 虽然如果你确定你总是会INSERT进入Countriesbefore Capitals(并且DELETE以相反的顺序)你可以添加一个FK约束 fromCapitals直接 to Countries,但这并没有真正增加任何好处,因为该Countries不能保证相应的Capitals行将存在。
  • 这种设计也与IDENTITYPK 兼容,只要记住只有前向声明表会有IDENTITY列,所有其他表都会有普通的intPK+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(如果不是彻底的 hack),因此永远不要让 EF 执行任何迁移或生成和运行任何 DDL ( CREATE TABLE.. .) 基于您的 Code-First 实体模型类的语句。
    • 虽然 EF 不再支持“数据库优先”模型,但您仍然可以使用“数据库中的代码优先”和代码优先代码生成,例如https://github.com/sjh37/EntityFramework-Reverse-POCO-Code- First-Generator(免责声明:这是我个人最喜欢的代码生成器,我是该项目的贡献者)。

    • 如果您使用这种方法在数据库上运行默认脚手架或代码优先代码生成,那么您最终会得到一个包含app1.Countries单独实体的app1.Capitals模型不想在你的 EF 模型中。app1.CountriesDeclapp1.ValidCountries

      • 在这种情况下,我会app1.*从 EF 中排除所有表,而是指示 EF 将VIEW dbo.Countries其视为单个实体(这是有道理的,因为从数学上讲,两个实体之间的每个 1:1关系都与定义为产品类型单个实体相同2 个其他实体)。
      • 因为 aVIEW没有 aPRIMARY KEY也没有任何FOREIGN KEY约束,EF(默认情况下)不能正确地从 a 代码生成实体类VIEW,但是前面提到的代码生成工具可以很容易地以正确的方式轻推 EF(查找下面的ViewProcessing方法和AddForeignKeys方法它)。
    • 如果您确实app1.Countriesandapp1.Capitals表保留为 EF 中的实体类型,请注意让 EF 执行INSERTinto 这两个表将失败,除非您的代码首先执行INSERTinto app1.CountriesDecl

    • 或者您可以添加一个CREATE TRIGGER Countries/Capitals_Insert ON app1.Countries/app1.Capitals INSTEAD OF INSERT将执行IF NOT EXIST ... INSERT INTO app1.CountriesDecl.

    • 但是,至少 EF 在这两张桌子上UPDATE不会有任何问题。DELETE


方法 2:只有一个额外的TABLE对象,但FK列是NULL-able - 并且 aVIEW用作隐藏无效/不完整行的窗帘。

  • 如果方法 1可以概括为从“对象必须始终是不可变的”学派中借用的思想,那么方法 2的灵感来自允许您就地改变现有对象的语言,以便编译器可以验证每个突变步骤改变对象的有效类型,使其满足某些类型约束。

    • 例如,考虑这个TypeScript(因为截至 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包含部分/不完整的对象CountryCapital我们可以自由插入/更新/删除的数据,因为它们的相互FOREIGN KEY约束是NULL-able,见下文。

    • 这些表被命名为dbo.CountriesDataanddbo.CapitalsData而不是dbo.Countriesdbo.Capitals分别表示这些表只包含任意“数据”而不是有效和正确的实体。这是我的个人命名约定。YMMV。
    • 方法 1一样,VIEW dbo.Countriesexists 仅将有效实体公开为单一产品类型
      • 或者,您还可以分别为 Country 和 Capitals 定义其他VIEW对象,并让 EF 也将它们视为实体(尽管您需要做更多的INSERT工作才能单独为每个视图工作)。
  • 但与方法 1不同的是,该dbo.CapitalsData表现在有一个复合主键,这是 OP 特定数据库设计目标的结果——这可能不适用于您的数据库。

    • 复合 PK 是必要的,以允许在强制执行约束的情况下具有dbo.CountriesNULL CountryName值。这是必须的,因为也是PK的,所以不能。这是因为 SQL Server 仅在 FK 中的所有列都为非. 如果您有不同的 PK 设计,那么这对您来说会有所不同。FK_CountriesData_to_CapitalsCountryNamedbo.CountriesDataNULLNULL
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一个新的国家...
      1. 首先INSERT INTO dbo.CountriesData是初始NULL CapitalName值。
      • 这没关系,因为当 FK 的值(或复合 FK 中至少有 1 个值)为NULL.
      1. 然后INSERT INTO dbo.CapitalsData(反之亦然,提供CountryName相反的情况NULL)。
      2. 只有在插入两行之后,您才能运行UPDATE dbo.CountriesData SET CapitalName = inserted.CapitalName WHERE CountryName = inserted.CountryName.
      3. 因此,您VIEW dbo.Countries现在将公开 now-valid1:1相关数据。
    • DELETE必须以相反的顺序执行操作(即首先UPDATE清除 FK,然后DELETE以任何顺序从每个表中清除)。
    • UPDATE操作不需要特殊处理。
  • 我注意到您实际上可以将所有上述INSERT逻辑移动到和表AFTER INSERT上的触发器中,因为这意味着: CountriesDataCapitalsData
    • UPDATEAFTER INSERT触发器就dbo.CapitalsData!(反之亦然) - 但一定要添加检查WHERE inserted.CountryName IS NOT NULL- 但如果你这样做,那么你的客户的 SQL 代码只需要执行两个INSERT语句,两个AFTER INSERT触发器之一将自动处理其余的,但前提是数据最终有效 - 因此它将在VIEW dbo.Countries.
    • 这种方法与 EF 配合得更好,因为您不需要对表格进行处理,因此对表格进行CountriesDecl单独INSERT操作不会失败 - 但请记住,这两个表格/实体之间没有关系。dbo.CountriesDatadbo.CapitalsData1:1
于 2021-08-23T23:09:01.987 回答
0

实现此目的的最简单方法是仅创建 1 个表,其中表 A 和 B 字段均不为空。这样就不可能有一个没有另一个。

于 2018-01-05T13:52:04.730 回答
-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)
)
于 2019-05-18T21:04:33.203 回答