如何在两个表之间共享相同的主键?

23

我正在阅读一本关于EF4的书籍,遇到了这个问题:

enter image description here

我想知道如何创建这个数据库,以便我可以按照书中的示例进行操作。

我该如何使用简单的TSQL命令创建这些表呢?假设已经存在数据库,不用考虑创建数据库的问题。


@Jeff:这本书没有展示TSQL,它假设这个数据库已经存在,因此才会有这个问题。 - Only Bolivian Here
你尝试过书中其他讲解如何创建数据库的章节吗?你接受了一个没有任何创建数据库代码的答案。 - JeffO
4个回答

46

你已经获得了代码。我想分享一些关于为什么你可能希望有两个表建立这样的关系的信息。

首先,当两个表具有相同的主键并且存在外键关系时,这意味着它们具有一对一的关系。那么为什么不将它们放在同一个表中呢?有几个原因,你可能会将一些信息拆分到单独的表中。

首先,这些信息在概念上是独立的。如果第二个表中包含的信息与特定关注点相关,则将数据存储在单独的表中更容易处理。例如,在你的示例中,他们将图像分离出来,即使他们只打算每个SKU仅有一条记录。这使你可以灵活地更改表结构以后变成一个一对多的关系,如果你决定需要多个图像。另外,这意味着当你查询仅针对图像时,你不必实际访问其他(可能更大的)表。

这就带我们来到第二个原因,你目前具有一对一的关系,但你知道未来的版本已经计划将其转换为一个一对多的关系。在这种情况下,将其设计为一个单独的表更容易,这样当你转换到该结构时,就不会破坏所有的代码。如果我打算这样做,我会先创建一个代理键作为主键,并在外键上创建一个唯一索引。这样,当你转换为一对多关系时,你只需删除唯一索引并将其替换为常规索引。

另一个将一对一关系拆分的原因是如果表变得过于宽阔。有时你对一个实体有太多的信息无法轻松地将其适应记录可容纳的最大大小。在这种情况下,你倾向于将最少使用的字段(或概念上相关的字段)移动到单独的表中。

另一个将它们分开的原因是,虽然你具有一对一的关系,但你可能不需要在父表中的大多数记录中都有子表中的内容记录。因此,你可以将其分开而不是在父表中添加许多空值。

其他人展示的代码假设您使用字符为基础的主键。如果您想要此类关系,但是您有自动生成的 Int 或 GUID,则需要仅在父表上进行自动生成。然后,您将该值存储在子表中,而不是在子表上生成新值。


3
感谢你抽出时间来撰写这篇文章,非常好的阅读体验。 :) - Only Bolivian Here

4

当说表共享相同的主键时,只是指每个表中都有一个同名字段,均设置为主键。

创建表格

CREATE TABLE [Product (Chapter 2)](
    SKU varchar(50) NOT NULL,
    Description varchar(50) NULL,
    Price numeric(18, 2) NULL,
    CONSTRAINT [PK_Product (Chapter 2)] PRIMARY KEY CLUSTERED 
    (
        SKU ASC
    )
)

CREATE TABLE [ProductWebInfo (Chapter 2)](
    SKU varchar(50) NOT NULL,
    ImageURL varchar(50) NULL,
    CONSTRAINT [PK_ProductWebInfo (Chapter 2)] PRIMARY KEY CLUSTERED 
    (
        SKU ASC
    )
)

Create Relationships

ALTER TABLE [ProductWebInfo (Chapter 2)] 
    ADD CONSTRAINT fk_SKU 
    FOREIGN KEY(SKU)
REFERENCES [Product (Chapter 2)] (SKU)

如果表名只是单词而不是关键字,比如表名只是ProductProductWebInfo,没有附加(Chapter 2),那么看起来会更简单一些。
ALTER TABLE ProductWebInfo
    ADD CONSTRAINT fk_SKU
    FOREIGN KEY(SKU)
REFERENCES Product(SKU)

你的第一句话有误导性。它与列名无关,而与关系有关,正如你在答案中后来正确指出的那样。 - Michael Haren
1
你说得对,我的术语有点生疏。这是我自己的错误假设。 - Jaymz

1
这只是我在SSMS中使用表设计器随意拼凑的一个示例,但应该可以给你一个想法(请注意末尾的外键约束):
CREATE TABLE dbo.Product
    (
    SKU int NOT NULL IDENTITY (1, 1),
    Description varchar(50) NOT NULL,
    Price numeric(18, 2) NOT NULL
    )  ON [PRIMARY]

ALTER TABLE dbo.Product ADD CONSTRAINT
    PK_Product PRIMARY KEY CLUSTERED 
    (
    SKU
    )

CREATE TABLE dbo.ProductWebInfo
    (
    SKU int NOT NULL,
    ImageUrl varchar(50) NULL
    )  ON [PRIMARY]

ALTER TABLE dbo.ProductWebInfo ADD CONSTRAINT
    FK_ProductWebInfo_Product FOREIGN KEY
    (
    SKU
    ) REFERENCES dbo.Product
    (
    SKU
    ) ON UPDATE  NO ACTION 
     ON DELETE  NO ACTION 

这对于这个简单的例子来说似乎有点过于复杂了。能不能把它简化到最基本的要素? - Only Bolivian Here
这是一个非常基础的代码。唯一真正缺失的是顶部的 CREATE DATABASE 语句。逻辑上,我们正在创建一个父表 (Product) 和一个子表 (ProductWebInfo)。然后,我们从子表的主键创建了一个外键指向父表。 - Bobby D
可能有所帮助的是,删除WITH(...)ON [...]dbo.GO部分。 - Michael Haren
@Michael 同意。我一直在考虑保留它们的价值,并最初决定使用设计师的默认输出,以便如果用户以后使用设计师时不会看起来混乱。然而,为了可读性,我已经将它们删除。感谢你的提示! - Bobby D

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接