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模式更改与应用程序层隔离开来。您还可以在视图上使用而不是插入、更新触发器。