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

时间:2012-05-20 15:26:29

标签: sql-server database tsql database-design relational-database

我只是需要一些确认是数据库设计像这样好或不。如果不是,我在这里做错了。
我有以下表格:

TableA{TableAID,...}
TableB{TableBID,...}
TableC{TableCID,...}
etc.

我有一张桌子,我喜欢某种'新闻Feed'。当我在任何表A,B,C中添加内容时,我还在此表中添加行。

Feed{FeedID, TypeID, ReferenceID,...}

FeedID是PK自动增量
TypeID是引用类型表的编号,根据此ID我知道该表中的行是表A,B,C。
ReferenceId是表A,B,C中项目的ID A,B,C表都有不同的字段 现在,当我想获取Feed数据时,我还需要从每个表中获取一些数据,以便在应用程序中使用它。在我的查询中,我使用了很多SELECT CASE CLAUSE,如:

我首先加入查询(A,B,C)中的所有表

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

enter image description here

3 个答案:

答案 0 :(得分:1)

如果没有将其用于特定目的,您的超类型子模型将被“逆转”。

enter image description here

所以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(和公共列)的列名。

select
      FeedID
    , Common_Column
    , A_Specific_Column
from vFeed;

enter image description here

请注意,执行计划仅显示FeedFeed_A个表,查询优化器消除了表_B_C;没必要碰那两个。

换句话说,您只需在查询中使用特定列就可以请求特定的Feed数据,并让优化程序对其他所有内容进行排序 - 您的示例中不需要CASE ... WHEN ..杂技。

答案 1 :(得分:0)

正如我在评论中所提出的(以及@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
);

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

答案 2 :(得分:0)

将您要显示的所有数据添加到Feed表格中的“新闻Feed”中。它是重复数据,但从长远来看,它将使您的生活更轻松。

它还可确保您的新闻源保持历史正确。这意味着当我更新三个表之一中的记录时,“旧”Feed数据保持不变,而不是使用新值更新。