【问题标题】:Inserting records in database tables using "inheritance"使用“继承”在数据库表中插入记录
【发布时间】:2011-07-15 22:54:10
【问题描述】:

我有一个表,它的主键也是另一个表主键的外键(即数据库中模拟的“继承”)。

/****** Object:  Table [dbo].[BaseClass]    Script Date: 07/15/2011 18:17:27 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[BaseClass](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Title] [nvarchar](50) NOT NULL,
    [Description] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_BaseClass] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

USE [TestConcepts]
GO

/****** Object:  Table [dbo].[DerivedTable]    Script Date: 07/15/2011 18:17:49 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[DerivedTable](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [SpecialProperty] [uniqueidentifier] NOT NULL,
 CONSTRAINT [PK_DerivedTable] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[DerivedTable]  WITH CHECK ADD  CONSTRAINT [FK_DerivedTable_BaseClass] FOREIGN KEY([ID])
REFERENCES [dbo].[BaseClass] ([ID])
GO

ALTER TABLE [dbo].[DerivedTable] CHECK CONSTRAINT [FK_DerivedTable_BaseClass]
GO

在这种情况下插入记录的正确方法是什么?显然,插入不会返回插入行的 PK(加上子表的 PK 也是标识)。

【问题讨论】:

    标签: sql-server database-design


    【解决方案1】:

    这里是这种模式的few examples

    子类型表应该有自增ID,该ID与超类型表中的ID匹配。

    基本技术(使用您的示例)看起来像

    DECLARE @MY_ID integer;
    INSERT INTO BaseTable(Title, Description)
        VALUES ('title_here', 'blah, blah');
    SELECT @MY_ID = SCOPE_IDENTITY();
    
    INSERT INTO DerivedTable(ID, SpecialProperty)
        VALUES (@MY_ID, newid()); -- the SpecialProperty is uniqueidentifier
    

    一种方法是创建一个视图,为每个子类型表创建一个视图,或者只创建一个视图。然后在视图上创建一个INSTEAD OF INSERT TRIGGER 并使用触发器内部的技术。

    您可能还会发现 this technique 对于捕获多个插入的 ID 也很有用。

    【讨论】:

      【解决方案2】:
      1. 没有人称其为“继承”。事实并非如此。这是一个关系,RDBMS 中的 R。

      2. INSERTs do 告诉你刚刚插入的行的 PK。查看 SQL Server 上的@@SCOPE_IDENTITY。

      【讨论】:

      • 首先,你说得对,它只是一个关系,但它是继承的模拟,许多人确实使用这个术语来指代这个构造。我在“继承”周围加上引号是有原因的。其次,SCOPE_IDENTITY 将完美运行。谢谢。
      • 几个在数据库中提到“继承”的链接:en.wikipedia.org/wiki/Single_Table_Inheritance, sqlteam.com/article/…
      • 会给你你的解释,但在这个行业相当可观的职业生涯中,我几乎从未见过它适用于这些类型的关系,除非表之间的关系是真正的继承关系(不经常)。
      • 在我的情况下,它具体是一种继承关系。也许如果我发布了我的实际表格,它会更加明显。 ;) 很抱歉造成混乱。
      【解决方案3】:

      DERIVEDCLASS 表可以有一个自动递增(标识)的 PK,但如果是这样,则必须有另一列作为外键引用返回 BASETABLE:

                BASETABLE
                id int pk autoincrement
                baseattribute1
                baseattribute2
                etc etc
      
      
                 DERIVEDTABLE
                 id  int pk autoincrement
                 **baseid**  foreign key references BASETABLE(id)
                 extendedattribute1
                 extendedattribute2
      

      这将允许每个基础实体的多个派生。如果需要,在 DERIVEDTABLE.baseid 上放置唯一索引或将 baseid 设置为 PK 可以防止这种情况发生。

      以下将实例化基类的成员及其派生实例和/或扩展属性(如果有的话)[它将取决于 baseid 在 DerivedTable 中是否具有唯一约束;如果是后者,它可能是与 BaseTable 一对一关系的 PK,而不是多对一]:

                select * from BASETABLE
                LEFT JOIN DERIVEDTABLE
                on BASETABLE.id = DERIVEDTABLE.baseid
      

      未扩展的基类实例在扩展属性列中将具有 NULL。

      要仅查找已扩展的实体,请使用内连接:

               select * from DERIVEDTABLE
               inner join BASETABLE
               on DERIVEDTABLE.baseid = BASETABLE.id
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-18
        • 2012-03-15
        • 1970-01-01
        • 1970-01-01
        • 2020-09-07
        • 1970-01-01
        • 2018-05-07
        相关资源
        最近更新 更多