Tables are usually divided into logically different “things”, so you don’t have the same “things” twice. For example, you do not want to:
[SensorReadings] Id : PK UpperLimit : FLOAT UpperLimitAlertDelay : INT LowerLimit : FLOAT LowerLimitAlertDelay : INT IsAnalog : BOOL AnalogValue : FLOAT IsOn : BOOL
Because you mix the sensor and the readings on the same line. The sensor is different from than his testimony:
[Sensors] [SensorReadings] Id Id UpperLimit SensorID UpperLimitAlertDelay Reading LowerLimit LowerLimitAlertDelay IsAnalog Manufacturer SerialNumber LastInspectionDate ...
One thing that I wouldn’t split the “sensors” into two tables. A sensor is a sensor, that is what it is. As a customer, a customer, or a song is a song. You will have a table of songs, not a table of classical songs and another table for everyone else. If you divide the sensors into two tables, you can assume that there are two sensors with the same ID . Sensors are unique objects, they must be in the same table, and they all have a unique identifier. The fact that the sensor is analog or digital is a property of the sensor.
Your question is unique - your sensors can have Readings in different logical formats; some are analog floating point values, others are digital logic values. You are struggling with how to store sensor “readings” when not all sensor readings correspond to the same data type of a logical column (i.e. Float vs bool). It comes down to practicality, and what's best for the system.
You can save all readings in a floating point number column:
[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
But now you need to know how to interpret the floating point value 0 , 1 as a logical on , off . Is it hard to do? I personally don’t think so. True, it does not fully use the data types available in the database engine, but I do not care. You will join SensorReadings with Sensors , so you will have an IsAnalog column to help you interpret. In other words:
SELECT Id, SensorID, Reading, Sensors.IsAnalog FROM SensorReadings sr INNER JOIN Sensors s ON sr.SensorID = s.SensorID
Give you pretty easy to parse the results:
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
You can even create an auxiliary view (or just a query) that decodes the readings as AnalogReading and 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
This will give you:
[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
It depends on who should deal with the results. I can easily imagine that the code first checks the IsAnalog column and then reads either AnalogReading or DigitalReading .
You could do what you originally proposed; split them into several tables. But now the problem is: how do you access data? It seems to me that if I had this system of sensor readings, at some point I would need to do something with them - to show them to the user. Now I have to jump through the hoops to reunite with the data:
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
gives you
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
In addition, “Id” is also difficult to decode, because two different readings may have the same “ID”. Reading is reading and must be unique.
The tradeoff you're probably looking for is what you originally had.
[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
Yes, this leaves you with a lot of (null) values, but the cost of joining the tables back together is a practical problem that your design decision should consider.
I think of it as a registry in Windows. A key contains a value . You do not care how this value is stored, as long as you can read it, because there is a logical type. To accomplish this in a database, I would use several columns of the data type and read them as needed.