表通常被拆分为逻辑上不同的“things”,因此您不会有两次相同的“things”。例如,您不希望:
[SensorReadings]
Id : PK
UpperLimit : FLOAT
UpperLimitAlertDelay : INT
LowerLimit : FLOAT
LowerLimitAlertDelay : INT
IsAnalog : BOOL
AnalogValue : FLOAT
IsOn : BOOL
因为您将传感器和它的读数混合在一行中。传感器是不同于其读数的事物:
[Sensors] [SensorReadings]
Id Id
UpperLimit SensorID
UpperLimitAlertDelay Reading
LowerLimit
LowerLimitAlertDelay
IsAnalog
Manufacturer
SerialNumber
LastInspectionDate
...
我不会这样做的一件事是将“传感器”分成两个表。传感器就是传感器,它就是这样。就像一个客户就是一个客户,或者一首歌就是一首歌。您将有一张歌曲表,而不是一张古典歌曲表,而另一张表则用于其他所有歌曲。如果您确实将传感器分成两个表,您可以想象有两个传感器具有相同的ID。传感器是唯一的实体,它们应该在同一个表中,并且都具有唯一的 ID。传感器是模拟还是数字的事实是传感器的属性。
您的问题是独一无二的 - 您的传感器可以有不同逻辑格式的读数;有些是模拟浮点值,有些是数字布尔值。当并非所有传感器读数都适合相同的逻辑列数据类型(即浮点数与布尔值)时,您正在为如何存储传感器的“读数”而苦苦挣扎。它归结为实用性,以及什么对系统最有利。
您可以将所有读数存储在浮点数列中:
[SensorReadings]
Id SensorID Reading
== ======== =======
1 3728 120.2
2 3728 120.3
3 89 1
4 89 0
5 3728 120.2
6 89 0
但是现在您必须知道将浮点值 0,1 解释为逻辑 on,off。这很难做到吗?我个人不这么认为。诚然,它没有充分利用数据库引擎中可用的数据类型,但我并不在乎。您将加入SensorReadings 和Sensors,因此您将拥有IsAnalog 列来帮助您解释。换句话说:
SELECT Id, SensorID, Reading, Sensors.IsAnalog
FROM SensorReadings sr
INNER JOIN Sensors s ON sr.SensorID = s.SensorID
会给你一个非常容易解析的结果集:
Id SensorID Reading IsAnalog
== ======== ======= ========
1 3728 120.2 false
2 3728 120.3 false
3 89 1 true
4 89 0 true
5 3728 120.2 false
6 89 0 true
您甚至可以创建一个帮助视图(或只是一个查询),将读数解码为AnalogReading 和DigitalReading:
CREATE VIEW SimpleSensorReadings AS
SELECT Id, SensorID, Reading AS RawReading,
CASE Sensors.IsAnalog
WHEN 0 THEN Reading
ELSE NULL
END AS AnalogReading,
CASE Sensors.IsAnalog
WHEN 1 THEN CAST(Reading AS BOOL)
ELSE NULL
END AS DigitalReading,
Sensors.IsAnalog
FROM SensorReadings sr
INNER JOIN Sensors s ON sr.SensorID = s.SensorID
这会给你:
[SimpleSensorReadings]
Id SensorID RawReading AnalogReading DigitalReading IsAnalog
== ======== ========== ============= ============== ========
1 3728 120.2 120.2 true
2 3728 120.3 120.3 true
3 89 1 true false
4 89 0 false false
5 3728 120.2 120.2 true
6 89 0 false false
这取决于谁必须处理结果。我可以很容易地想象代码首先检查“IsAnalog”列,然后根据需要读出AnalogReading 或DigitalReading。
你可以按照你最初的建议去做;将它们分成多个表。但现在问题变成了:你如何访问数据?在我看来,如果我有这个传感器读数系统,在某些时候我将不得不对它们做点什么——把它们展示给用户。现在我必须跳过障碍重新加入数据:
SELECT ID, AnalogSensorID AS SensorID,
Value AS RawReading, Value AS AnalogReading,
true AS IsAnalog
FROM AnalogSensorReadings
UNION ALL
SELECT ID, SwitchSensorID AS SensorID,
CAST(IsOn AS float) AS RawReading, null AS AnalogReading, IsOn AS DigitalReading,
false AS IsAnalog
给你
Id SensorID RawReading AnalogReading DigitalReading IsAnalog
== ======== ========== ============= ============== ========
1 3728 120.2 120.2 true
2 3728 120.3 120.3 true
1 89 1 true false
2 89 0 false false
3 3728 120.2 120.2 true
3 89 0 false false
除了现在“Id”也很难解码,因为两个不同的读数可以有相同的“ID”。读书就是读书,应该是独一无二的。
您可能正在寻找的折衷方案是您最初拥有的。
[SensorReadings]
Id SensorID AnalogReading DigitalReading
== ======== ============= ==============
1 3728 120.2
2 3728 120.3
3 89 true
4 89 false
5 3728 120.2
6 89 false
是的,这会给您留下很多 (null) 值 - 但是将表重新连接在一起的费用是一个实际问题,必须考虑到您的设计决策。
我认为它就像 Windows 中的注册表。 key 包含 value。您并不真正关心该值的存储方式,只要您可以读取它,因为类型在逻辑上是这样的。为了在数据库中实现这一点,我将使用多个数据类型列,并根据需要读取它们。