Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 设计多个表之一的外键_Sql_Sql Server_Database_Database Design_Entity Framework Core_Shared Primary Key_Class Table Inheritance - Fatal编程技术网

Sql 设计多个表之一的外键

Sql 设计多个表之一的外键,sql,sql-server,database,database-design,entity-framework-core,shared-primary-key,class-table-inheritance,Sql,Sql Server,Database,Database Design,Entity Framework Core,Shared Primary Key,Class Table Inheritance,我有三个表:客户、提供商和位置。我需要创建第四个名为Contacts的表 我希望有任意数量的联系人与客户、提供商和位置表中的任何行相关联,因此我最终得到了类似的结果 CREATE TABLE [dbo].[Contacts] ( [Id] INT IDENTITY (1, 1) NOT NULL, [CustomerId] INT NULL, [ProviderId] INT NULL,

我有三个表:
客户
提供商
位置
。我需要创建第四个名为
Contacts
的表

我希望有任意数量的
联系人
客户
提供商
位置
表中的任何行相关联,因此我最终得到了类似的结果

CREATE TABLE [dbo].[Contacts] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [CustomerId] INT            NULL,
    [ProviderId] INT            NULL,
    [LocationId] INT            NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL,
);
我觉得这个不太优雅。除了有未使用的列之外,我可能还应该添加一个约束,以确保
CustomerId
ProviderId
LocationId
中的一个不为
NULL

另一种方法是创建多对多联接表。这将不需要任何未使用的列。但这似乎仍然是一种浪费,因为任何联系人都不会涉及多家公司


有人知道任何更巧妙的解决方案吗?

另一种方法是恢复关系,并为联系人可能涉及的每个实体创建一个映射表,如:

CREATE TABLE [dbo].[Contacts] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL
);

CREATE TABLE [dbo].[ContactCustomers] ( 
    [ContactId]  INT NOT NULL REFERENCES Contacts([ContactId]),
    [CustomerId] INT NOT NULL REFERENCES Customers([CustomerId]),
    PRIMARY KEY([ContactId], [CustomerId])
);

CREATE TABLE [dbo].[ContactProviders] ( 
    [ContactId]  INT NOT NULL REFERENCES Contacts([ContactId]),
    [ProviderId] INT NOT NULL REFERENCES Providers([ProviderId]),
    PRIMARY KEY([ContactId], [ProviderId])      
);

CREATE TABLE [dbo].[ContactLocations] ( 
    [ContactId]  INT NOT NULL REFERENCES Contacts([ContactId]),
    [LocationId] INT NOT NULL REFERENCES Locations([LocationId]),
    PRIMARY KEY([ContactId], [LocationId])      
);

这在关系方面为您提供了充分的灵活性,同时保持
联系人表专注于其主要目的:存储与该实体相关的数据。

除了@GMB的建议外,另一种选择是简单地拥有不同的联系人表。仅仅因为地点和客户都有联系人,而且他们最初具有相同的属性,并不意味着他们必须存储在同一个表中

如果您不打算查询所有联系人,那么像这样单独存储它们会更有效。三者的模式可能会随着时间的推移而发生分歧

如果您想在联系人类型上编写通用逻辑,它们甚至可以在应用程序中共享一个NotMapped的Contact超类

乙二醇


联系人是对客户、提供商和地点的概括。这里有一些技巧你可能会发现很有用。和。

这似乎与我的第二个多对多联接表想法相同,尽管它实际上不是多对多关系。当然有可能,如果没有我所希望的那么高效和简洁的话。正如@DaleK所建议的,没有一个真正的灵巧的方法来解决这个问题。我决定采用这种方法,主要是因为通过约束更容易确保数据的有效性。我不认为这是基于观点的。问题基本上是“此方案的合理备选方案是什么?”,这是一个有效的技术问题。@DavidBrowne Microsoft但有多种备选方案,并且所有备选方案都要权衡,因此最终取决于设计决策。@JonathanWood网站就是这样工作的。。。为什么有一个选项可以关闭“基于意见的”。@philipxy:这并不是真正解决同一件事,尽管将PK作为FK的中间表的想法肯定是可以采取的一种方法。我同意这既有趣又有用。。。但是你已经有了两个答案(还有更多的可能性),这两个答案都完全解决了问题,那么你将如何选择一个答案呢?无论如何,我没有投票决定结束,我只是指出了可能性,因为我已经看到很多这样的问题结束了——因为没有一个答案。是的,这会奏效,而且在某些方面很简单。但就优雅或效率而言,它的得分并不高。只要你不需要查询所有类型的联系人,它是最有效的。GMB的解决方案需要一个额外的连接来获取联系人,以及contacts.Id上的主键,这两者都可以在这里省略,因为联系人的Id是集群主键的尾随键。每个实体的联系人将一起存储在聚集索引中,因此
从CustomerContacts中选择*,其中CustomerId=@CustomerId
将花费4-5个逻辑IO。句号。@DavidBrowne微软:我同意你说的。但效率也可能与表示数据所需的表和列的数量有关。我不仅仅是在考虑性能。@JonathanWood从另一个角度来看,这是唯一一种使相应的联系人条目归其“家长”所有的设计,因此可以根据特定家长自由添加、删除或修改。也会随父项自动删除。在公认的方法中,联系人是单独的实体,可以在客户、提供商和地点之间共享。它们中没有一个“拥有”它,因此无法自动删除它,修改将影响其他人。我并不是说这是不好的,这只是一个不同于原来的行为(限制是只设置了一个FK)。@IvanStoev:是的,我可以看到。级联删除无法完全实现,孤立联系人肯定是可能的。
CREATE TABLE [dbo].[CustomerContacts] (
    [CustomerId] INT            not null references Customer on delete cascade,
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL,
    constraint pk_CustomerContacts primary key (CustomerId,Id)
);
CREATE TABLE [dbo].[ProviderContacts] (
    [ProviderId] INT            not null references Provider on delete cascade,
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL,
    constraint pk_ProviderContacts primary key (ProviderId,Id)
);
CREATE TABLE [dbo].[LocationContacts] (
    [LocationId] INT            not null references Location on delete cascade,
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL,
    constraint pk_LocationContacts primary key (LocationId,Id)
);