Sql server 一对多动态数据库关系问题

Sql server 一对多动态数据库关系问题,sql-server,database,tsql,database-design,relational-database,Sql Server,Database,Tsql,Database Design,Relational Database,我只需要确认一下数据库的设计是否符合要求。如果不是的话,我在这里做错了什么。 我有以下表格: TableA{TableAID,...} TableB{TableBID,...} TableC{TableCID,...} etc. 我有一张桌子,我用它来做“新闻提要”。当我在任何表A、B、C中添加某些内容时,我也会在这个表中添加行 Feed{FeedID, TypeID, ReferenceID,...} FeedID是自动递增的 TypeID是引用表格类型的编号,根据这个ID,我知道是表格A

我只需要确认一下数据库的设计是否符合要求。如果不是的话,我在这里做错了什么。 我有以下表格:

TableA{TableAID,...}
TableB{TableBID,...}
TableC{TableCID,...}
etc.
我有一张桌子,我用它来做“新闻提要”。当我在任何表A、B、C中添加某些内容时,我也会在这个表中添加行

Feed{FeedID, TypeID, ReferenceID,...}
FeedID是自动递增的 TypeID是引用表格类型的编号,根据这个ID,我知道是表格A、B、C中表格中的行。 ReferenceId是表A、B、C中项目的ID。 A、 B、C表都有不同的字段。 现在,当我想要获取提要数据时,我还需要从每个表中获取一些数据,以便在应用程序中使用。在我的查询中,我使用了lot SELECT CASE子句,如:

我首先连接到查询A、B、C中的所有表

...
CASE Feed.TypeId              
               WHEN 1 THEN tableA.someData
                           WHEN 2 THEN tableB.someData
                           WHEN 3 THEN tableC.someData
          END AS Data,
...

正如我在评论中所建议的,加上@Andomar的智慧,我认为这样做会更好:

CREATE TABLE dbo.FeedTypes
(
  FeedTypeID INT IDENTITY(1,1) PRIMARY KEY,
  SomedataA INT,
  SomedataB VARCHAR(32),
  SomedataC DATETIME
  --, ... other columns
);

CREATE TABLE dbo.Feeds
(
  FeedID INT IDENTITY(1,1) PRIMARY KEY,
  FeedTypeID INT NOT NULL FOREIGN KEY
    REFERENCES dbo.FeedTypes(FeedTypeID)
  --, ... other columns
);

您可以使用复杂的检查约束或触发器强制给定类型的相关列中存在/不存在数据。但是,如果提要可以很容易地更改类型,那么您必须拥有相当复杂的逻辑,就像在当前模型中一样。

将您希望在提要表中的新闻提要中显示的所有数据添加到提要表中。这是重复的数据,但从长远来看,它会让你的生活变得更加轻松


它还确保您的新闻提要保持历史上的正确性。这意味着当我更新三个表中的一个记录时,旧的提要数据保持不变,而不是用新值更新

在不考虑此模型是否适合特定用途的情况下,您的超类型子类型模型是相反的

所以DDL看起来像

CREATE TABLE Feed ( 
      FeedID               integer  IDENTITY(1,1) not null
    , FeedType             char(1)  not null
  --  Common_Columns_Here
    , Common_Column        varchar(20)
);
ALTER TABLE Feed ADD CONSTRAINT pk_Feed PRIMARY KEY (FeedID) ;


CREATE TABLE Feed_A ( 
      FeedID               integer  not null
  --  A_Specific_Columns_Here
    , A_Specific_Column    varchar(20)
);
ALTER TABLE Feed_A ADD
  CONSTRAINT  pk_Feed_A PRIMARY KEY (FeedID)
, CONSTRAINT fk1_Feed_A FOREIGN KEY (FeedID) REFERENCES Feed(FeedID) ;


CREATE TABLE Feed_B (
      FeedID               integer  not null
  --  B_Specific_Columns_Here
    , B_Specific_Column    varchar(20)
);
ALTER TABLE Feed_B ADD 
  CONSTRAINT  pk_Feed_B PRIMARY KEY (FeedID)
, CONSTRAINT fk1_Feed_B FOREIGN KEY (FeedID) REFERENCES Feed(FeedID) ;


CREATE TABLE Feed_C ( 
      FeedID               integer  not null
  --  C_Specific_Columns_Here
    , C_Specific_Column    varchar(20)
);
ALTER TABLE Feed_C ADD 
  CONSTRAINT  pk_Feed_C PRIMARY KEY (FeedID)
, CONSTRAINT fk1_Feed_C FOREIGN KEY (FeedID) REFERENCES Feed(FeedID) ;
现在,为了读取此结构,首先创建一个视图

create view vFeed as
select
      f.FeedID
    , FeedType
    , Common_Column
    , A_Specific_Column
    , B_Specific_Column
    , C_Specific_Column
from      Feed   as f
left join Feed_A as a on (a.FeedID = f.FeedID and f.FeedType = 'A')
left join Feed_B as b on (b.FeedID = f.FeedID and f.FeedType = 'B')
left join Feed_C as c on (c.FeedID = f.FeedID and f.FeedType = 'C')
;
看看当我想要选择我知道是来自feed A的数据时会发生什么。注意,在这个查询中没有指定FeedType,只有属于feed_A和common列的列名

select
      FeedID
    , Common_Column
    , A_Specific_Column
from vFeed;
注意,执行计划只显示Feed和Feed_A表,查询优化器消除了表_B和_C;不用碰那两个


换句话说,只需在查询中使用特定列,您就可以请求特定的提要数据,并让优化器对其他内容进行排序—无需使用CASE。。。什么时候示例中的技巧。

1:1 exension表用于相当复杂的查询。我想要一张单人桌。对于与每个提要类型不相关的属性,使用可为空的列。为什么A、B和C是独立的表?为什么不让一个表具有一个type属性,而不是抽象它并使模型复杂化?如果您必须编写包含基于表的其他列的查询,那么这些查询可能会由于包含基于类型的其他列而变得类似复杂。换句话说,正如@Andomar所建议的,所有可能的列都在另一个表中,有些列根据类型可以为空。因为它们是独立的实体,A可以有10列、B3列和C5列。为什么你认为它是相反的?如果我这样设计,那么当我得到所有提要时,我就不知道要加入哪个表,因为我在另一个表中没有项的ID。@1100若要加载此结构,请先插入提要表以获得提要ID,然后插入到_A,_B,_C中的一个。我建议使用一个存储过程来处理这个问题。通过这种方式—通过读取视图和加载sp—可以将DB模式更改与应用程序层隔离开来。您还可以在视图上使用而不是插入、更新触发器。