2

假设我有一个 Table1,包含三列:ID(主键、身份)、A 和 B

现在,假设我有 3 种方法,假设它们在列方面没有任何共同之处:

方法一:C、D、E

方法 2:F、G、H、I

方法3:J

我可以制作一张表:ID、A、B、C、D、E、F、G、H、I、J、M

其中 M 是方法的名称(或方法 ID)。

但是,如果 90% 的时间使用方法 3,则会有很多空值。
这是一个问题吗?如果是这样,有没有更好的方法来设置它?

如果我让每个方法都有自己的表实体,我如何确保每个 ID 都有一个与之匹配的方法?

如果我将其保留为一张表,如果 M 为 1,我如何确保仅填写 C、D、E 并且 F 到 J 为 NULL?


好的,似乎有些人很难抽象地思考,所以我将创建一个随机的具体示例来应用上述内容:

假设我有人们进行锻炼的记录。
每条记录总是有一个 ID(用于唯一标识事件)、一个 TIME_STARTED 和 TIME_ENDED。

但是,根据他们进行的练习,需要不同的属性。假设只有三个练习:

椭圆机:INCLINE、LEVEL、SPEED

仰卧起坐:User_Weight、Reps、Delay、Extra_Weight

硬拉:Weight_Lifted

对于每个 ID,可能只有一个“方法”。应用这一点,请参阅上述问题。

4

2 回答 2

3

It sounds like you have a supertype/subtype situation here. In this case, Table1 holds your supertype, and you would want to create a different table to hold each of your subtypes. The PK on these subtype tables would also be an FK to the supertype table. So you would have something like this:

Supertype_table
|    ID(PK)   |  A  |  B  |

Subtype1_table
|  ID(PK&FK)  |  C  |  D  |  E  |

Subtype2_table
|  ID(PK&FK)  |  F  |  G  |  H  |  I  |

Subtype3_table
|  ID(PK&FK)  |  J  |

The point of this schema is to make sure that you don't have a bunch of rows which are mostly nulls. For each method, you would have to write a separate query that would insert/update the appropriate table. With SQL Server, you can make a view which combines all these tables and abstracts away any joins:

CREATE VIEW MyView
SELECT Super.ID, Super.A, Super.B, 
Sub1.C, Sub1.D, Sub1.E, 
Sub2.F, Sub2.G, Sub2.H, Sub2.I, 
Sub3.J
FROM Supertype_table as Super
LEFT OUTER JOIN Subtype1_table as Sub1 on Super.ID = Sub1.ID
LEFT OUTER JOIN Subtype2_table as Sub2 on Super.ID = Sub2.ID
LEFT OUTER JOIN Subtype3_table as Sub3 on Super.ID = Sub3.ID

So then you could just write something like:

SELECT ID, A, B, J
FROM MyView
WHERE J is not null

EDIT : For OP's comment

In order to ensure that each ID is in one and only one table, you need some kind of identifier on the supertype table. So if you had a column called TypeID, you would create the function:

CREATE FUNCTION [dbo].[SubtypeofSuperID](@ID int)
RETURNS int
AS
BEGIN
  DECLARE @TypeID int;

    SELECT @TypeID = TypeID 
    FROM Supertype_table
    WHERE ID = @ID

  RETURN @TypeID 
END

Then, using that, you can create a check on each of the subtype tables:

ALTER TABLE Subtype1_table CONSTRAINT [CK_CorrectSubtype1]
CHECK ( [dbo].[SubtypeofSuperID]([ID]) = 1 )
ALTER TABLE Subtype2_table CONSTRAINT [CK_CorrectSubtype2]
CHECK ( [dbo].[SubtypeofSuperID]([ID]) = 2 )
ALTER TABLE Subtype3_table CONSTRAINT [CK_CorrectSubtype3]
CHECK ( [dbo].[SubtypeofSuperID]([ID]) = 3 )
于 2012-06-15T19:04:12.100 回答
1

有几种方法...

首先,Jason 的回答是其中之一——将你的设计分成多个表——这对于大多数事情来说都是一个很好的方法。(又名更“标准化”的方法)

备择方案...

1)您可以在最后一个字段中包含一串名称-值对。例如:

ID   Method   DateTimeStart   DateTimeEnd   ValueString
1    1        2012-01-01...   2012-01-01... C:value,D:value,E:value
2    2        2012-01-01...   2012-01-01... F:value,G:value,H:value,I:value

因此,在您无法提前计划值类型的情况下,这可能会很方便。例如,也许您需要能够即时决定开始为方法 1 记录“W”值,而像在更规范化的设计中那样进行结构模型是不可行的。

这是我们的电子签名表单开发人员使用的常用方法。您可以想象一个网络表单,例如“部门休假申请”,有人将填写并以电子方式发送以供批准。然后出现了一个客户,他希望他们构建一个“采购订单”网络表单,该表单将具有必须记录的不同字段和值。他们没有为此创建一个全新的表(或向现有表添加列等),而是使用名称-值-对模型将所有表单数据存储在同一个表中,无论它是哪种形式。

2)如果您不信任在单个大表上运行插入的人员/进程,您可以使用表触发器来强制执行完整性。例如,更新前触发器可以检查方法编号,然后通过取消任何不适当的数据值来修改人员或进程试图插入的数据。

FWIW

于 2012-06-15T19:36:16.897 回答