The*_*uad 6 index sql-server-2008 foreign-key database-design
这是 IT 资产的库存数据库。所使用的模型经过修整,以专注于手头的问题。使用 SQL Server 2008。感谢您抽出时间阅读并提供您可以提供的任何输入。
我的设计包括一个Device表格,其中包含可以输入库存的各种设备。每个设备都有一个布尔标志,CanNetwork表明设备是否具有网络能力,例如,对于大多数计算机CanNetwork = true,对于硬盘驱动器CanNetwork = false;有些打印机是真的,有些是假的。你明白了。
该CanNetwork字段确定创建库存记录时与网络相关的信息是否相关。
我的第一个设计在表上使用索引Device.DeviceID并Device.CanNetwork在外键约束中使用Asset。

NetworkStatus在此设置中,该表如下所示:
+----------------------------------------------------------------------+
| NetworkStatusID | NetworkStatus | NetworkStatusDescription |
|----------------------------------------------------------------------|
| 1 | Connected | Device connected to network. |
| 2 | Not Connected | Device not connected to network. |
| 3 | Do Not Connect | Do not connect device to network. |
+----------------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
我在Asset表上放置了如下检查约束,以确保只有在设备能够连接到网络时才能提供网络状态和网络信息。
-- Asset table check constraint: CK_CanNetwork
-- If can't network, then network fields are null
CanNetwork = 0
AND NetworkStatusID IS NULL
AND Hostname IS NULL
AND IPAddress IS NULL
AND MACAddress IS NULL
OR CanNetwork = 1
-- Asset table check constraint: CK_NetworkStatus
-- If network status is "Connected", then must provide
-- a hostname or ip address
NetworkStatusID = 1 AND Hostname IS NOT NULL
OR NetworkStatusID = 1 AND IPAddress IS NOT NULL
OR NetworkStatusID <> 1
Run Code Online (Sandbox Code Playgroud)
我对这个设计的问题是我不确定与Asset和 Device.DeviceID/的关系Device.CanNetwork是好的还是坏的设计决定。像CanNetwork其他表一样传播非关键字段是一种糟糕的设计吗?我没有足够的数据库设计经验来做出明智的决定。
在这个设计中,我想我会使用桥/关联/连接表来决定哪些网络状态对设备有效。它看起来像这样:

该NetworkStatus表在此设置中如下所示(注意添加了 ID 为 #4 的记录,以及ForCanNetwork指定此状态用于可以连接到网络的设备的字段):
+--------------------------------------------------------------------------------------+
| NetworkStatusID | NetworkStatus | NetworkStatusDescription | ForCanNetwork |
|--------------------------------------------------------------------------------------|
| 1 | Connected | Device connected to network. | True (1) |
| 2 | Not Connected | Device not connected to network. | True (1) |
| 3 | Do Not Connect | Do not connect device to network. | True (1) |
| 4 | Incapable | Cannot connect to networks. | False (0) |
+--------------------------------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
由于此设计的粒度,理论上我可以允许具有此设计的设备的任何状态混合,但我想控制它,因此我编写了一些触发器,仅根据设备是否具有网络功能插入正确的状态混合。触发如下:
-- NetworkStatus table on INSERT trigger
-- Adds a record for each device that
-- matches the capability of the network status
INSERT INTO DeviceNetworkStatus
SELECT i.NetworkStatusID, dev.DeviceID
FROM Device dev
CROSS JOIN
inserted i
WHERE dev.CanNetwork = i.ForCanNetwork
-- Device table on INSERT trigger
-- Adds a record for each network status that
-- matches the capability of the new device
INSERT INTO DeviceNetworkStatus
SELECT ns.NetworkStatusID, i.DeviceID
FROM NetworkStatus ns
CROSS JOIN
inserted i
WHERE ns.ForCanNetwork = i.CanNetwork
Run Code Online (Sandbox Code Playgroud)
我在Asset表上使用了以下 CHECK 约束:
-- Asset table check constraint: CK_NetworkStatus
-- If network status is "Connected', then must provide
-- a hostname or ip address
-- If network status is "Incapable", then network fields
-- must be null
NetworkStatusID = 1 AND Hostname IS NOT NULL
OR NetworkStatusID = 1 AND IPAddress IS NOT NULL
OR NetworkStatusID = 4 AND Hostname IS NULL
AND IPAddress IS NULL AND MACAddress IS NULL
OR NetworkStatusID <> 1 AND NetworkStatusID <> 4
Run Code Online (Sandbox Code Playgroud)
这种设计消除了CanNetwork跨表传播的需要。我在这个设计中看到的问题是,每个具有网络功能的设备都会有DeviceNetworkStatus与NetworkStatusid 1、2 和 3配对的记录,而无法连接到网络的设备将仅与NetworkStatusid 4配对。这似乎是一个很多额外的记录都意味着同样的事情:可以联网的设备只能使用状态 1、2 和 3,不能联网的设备只能使用 4。这种设计似乎更“关系正确”,但也有点味道。
以下更新提出了设计 1 的变体。我经常遇到这样的情况,有很多方法可以实现相同的最终结果。我永远不知道如何判断设计是否存在隐藏的问题,我无法判断何时进行规范化或非规范化。这些设计中的一个是否比另一个更受欢迎?为什么?

-- NetworkAsset table check constraint: CK_CanNetwork
CanNetwork = 1
-- NetworkAsset table check constraint: CK_NetworkStatus
-- If network status is "Connected", then must provide
-- a hostname or ip address
NetworkStatusID = 1 AND Hostname IS NOT NULL
OR NetworkStatusID = 1 AND IPAddress IS NOT NULL
OR NetworkStatusID <> 1
Run Code Online (Sandbox Code Playgroud)

郑重声明,这个设计即使在我看来也有点荒谬,但这是我的思考过程。在这个表DeviceID中,NetworkDevice表中存在 a相当于CanNetwork在设计 1 中说= true。NetworkAsset.NetworkDeviceID具有外键约束,用于确保仅输入可联网设备。可以使用 CHECK 约束(见下文)并通过创建NetworkDeviceID一个等于 的计算列来做到这一点DeviceID。
-- NetworkAsset table check constraint: CK_IsNetworkDevice
NetworkDeviceID = DeviceID
Run Code Online (Sandbox Code Playgroud)
小智 1
我给你一个惊喜:你CanNetwork根本不需要!
您有两组设备:所有设备和可以连接到网络的设备。只有后者才有网络状态,并且该状态只能是两个值之一:已连接和未连接。(也可能有管理值,例如允许连接到哪个网络,或其网络掩码等。这些属性也不适用于非联网设备。)
NetworkedDevices 表中设备的存在表明它可以连接到网络。不在该表中意味着它不能;这就是所谓的封闭世界假设。
一般来说,指示事物是否与另一个表有关系的布尔值列的存在暗示您需要两个表而不是一个标志。
HTH。