patternsqlMinor
Computed Column Update when Table Value changes
Viewed 0 times
computedupdatecolumnvaluechangeswhentable
Problem
I have environmental sensors collecting some raw data from environmental stations. In addition to the sensors, there is a physical gauge measuring water height (staff gauge).
I'm trying to set up the staff gauge calculation, so that it will take the most recent offset reading from Table 2 and apply it to any new measurements coming in, without changing the previously calculated values.
Table 1
station_time
Air_temp_celcius
Rainfall_mm
pressure_mH20
water_temp_celcius
sensor_depth_mH20
staff_gauge_height_m (calculated, sensor_depth_mH20 + Offset from Table2)
Table 2
Observed_time
Offset_m
comments
My thinking was to have a function to pull the offset
Is there a way to have it only update new values coming into Table 1 without updating previous values when a new offset is entered? New offsets are entered into Table 2 very sporadically as field crews visit the site.
Additional information from comments:
There is no direct relationship between the two tables, other than the latest offset is used to calculate the staff gauge value. It should always use the most recent value.
I have specific stations and specific station offset tables. I generalized the table structure: table1_stream1 and table2_stream1_offset. As for the offset storage on the table, redundancy. Always was taught you normalize as much as possible and don't duplicate data in multiple tables if you can avoid it. I no longer work on coding and databases as much as I'd like, but some stuff sticks.
Are you saying if you have a station called "Antartica" and a station called "Africa" then you have the following tables: Antartica_stream1, Antartica_stream1_offset, Africa_stream1, and Africa_stream1_offset, etc.?
Correct. Given stations are polling hourly and not all locations carry the exact same sensor package (or sensors are in different order). Also individual stations may go offline due to technical or environmental issues.
I'm trying to set up the staff gauge calculation, so that it will take the most recent offset reading from Table 2 and apply it to any new measurements coming in, without changing the previously calculated values.
Table 1
station_time
Air_temp_celcius
Rainfall_mm
pressure_mH20
water_temp_celcius
sensor_depth_mH20
staff_gauge_height_m (calculated, sensor_depth_mH20 + Offset from Table2)
Table 2
Observed_time
Offset_m
comments
My thinking was to have a function to pull the offset
SELECT TOP 1(Offset)
FROM Table2
ORDER BY Observed_time DESCIs there a way to have it only update new values coming into Table 1 without updating previous values when a new offset is entered? New offsets are entered into Table 2 very sporadically as field crews visit the site.
Additional information from comments:
There is no direct relationship between the two tables, other than the latest offset is used to calculate the staff gauge value. It should always use the most recent value.
I have specific stations and specific station offset tables. I generalized the table structure: table1_stream1 and table2_stream1_offset. As for the offset storage on the table, redundancy. Always was taught you normalize as much as possible and don't duplicate data in multiple tables if you can avoid it. I no longer work on coding and databases as much as I'd like, but some stuff sticks.
Are you saying if you have a station called "Antartica" and a station called "Africa" then you have the following tables: Antartica_stream1, Antartica_stream1_offset, Africa_stream1, and Africa_stream1_offset, etc.?
Correct. Given stations are polling hourly and not all locations carry the exact same sensor package (or sensors are in different order). Also individual stations may go offline due to technical or environmental issues.
Solution
Given the additional information that Aaron Bertrand didn't have access to when he posted his answer I would suggest a different tack.
Instead of putting logic/business significance in table names I would have general table names and put the logic/business significance in attributes/data in the tables. This should make it easier to expand functionality, and maintain your data. Furthermore you can extract useful information much easier.
The following is a rough schema that captures the direction I recommend and will probably need to be adapted to your exact needs:
Now you can add a new station without duplicating table schema, you can easily compare data from related stations, etc.
Even if you didn't want/can't change your schema, I would recommend putting the calculation in a view. That is more obvious in my opinion than a trigger, and it would be easier to trouble shoot for me. Something like the following should work with my schema above:
This will be easy to troubleshoot, hard to miss, and obvious to future maintainers. You could modify this code to work for your current schema too, but would have to duplicate it for each station. In that case I would still recommend this approach for the above stated reasons.
Instead of putting logic/business significance in table names I would have general table names and put the logic/business significance in attributes/data in the tables. This should make it easier to expand functionality, and maintain your data. Furthermore you can extract useful information much easier.
The following is a rough schema that captures the direction I recommend and will probably need to be adapted to your exact needs:
CREATE TABLE dbo.WeatherStation
(
WeatherStationId INT NOT NULL PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(50) NOT NULL -- This is where you put the name of the station instead of in the table.
)
CREATE TABLE dbo.SensorReading
(
SensorReadingId INT NOT NULL PRIMARY KEY IDENTITY(1,1),
WeatherStationId INT NOT NULL FOREIGN KEY REFERENCES dbo.WeatherStation(WeatherStationId), -- Match a reading to the station
ReportedTime DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(), -- When the time was reported to the database
)
CREATE TABLE dbo.SensorOffset
(
SensorOffsetId INT NOT NULL PRIMARY KEY IDENTITY(1,1),
WeatherStationId INT NOT NULL FOREIGN KEY REFERENCES dbo.WeatherStation(WeatherStationId), -- Match a reading to the station like you do now
Offset DECIMAL(20, 10) NOT NULL -- Adjust precision/datatype as needed
Comment NVARCHAR(500) NULL,
Created DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME() -- This would need to be unique per weather station
)Now you can add a new station without duplicating table schema, you can easily compare data from related stations, etc.
Even if you didn't want/can't change your schema, I would recommend putting the calculation in a view. That is more obvious in my opinion than a trigger, and it would be easier to trouble shoot for me. Something like the following should work with my schema above:
;WITH CurrentOffset_CTE AS
(
SELECT
WeatherStationId
, MAX(Created) AS Created
FROM dbo.SensorOffset
GROUP BY
WeatherStationId
)
SELECT
WS.Name
, SR.ReportedTime
, CASE WHEN SR. IS NOT NULL THEN SR. + SO.Offset ELSE NULL END AS
,
FROM dbo.WeatherStation WS
INNER JOIN dbo.SensorReading SR ON SR.WeatherStationId = WS.WeatherStationId
INNER JOIN CurrentOffset_CTE CO ON CO.WeatherStationId = WS.WeatherStationId
INNER JOIN dbo.SensorOffset SO ON SO.WeatherStationId = CO.WeatherStationId AND SO.Created = CO.CreatedThis will be easy to troubleshoot, hard to miss, and obvious to future maintainers. You could modify this code to work for your current schema too, but would have to duplicate it for each station. In that case I would still recommend this approach for the above stated reasons.
Code Snippets
CREATE TABLE dbo.WeatherStation
(
WeatherStationId INT NOT NULL PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(50) NOT NULL -- This is where you put the name of the station instead of in the table.
)
CREATE TABLE dbo.SensorReading
(
SensorReadingId INT NOT NULL PRIMARY KEY IDENTITY(1,1),
WeatherStationId INT NOT NULL FOREIGN KEY REFERENCES dbo.WeatherStation(WeatherStationId), -- Match a reading to the station
ReportedTime DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(), -- When the time was reported to the database
<Other columns like temp, pressure, etc.>
)
CREATE TABLE dbo.SensorOffset
(
SensorOffsetId INT NOT NULL PRIMARY KEY IDENTITY(1,1),
WeatherStationId INT NOT NULL FOREIGN KEY REFERENCES dbo.WeatherStation(WeatherStationId), -- Match a reading to the station like you do now
Offset DECIMAL(20, 10) NOT NULL -- Adjust precision/datatype as needed
Comment NVARCHAR(500) NULL,
Created DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME() -- This would need to be unique per weather station
);WITH CurrentOffset_CTE AS
(
SELECT
WeatherStationId
, MAX(Created) AS Created
FROM dbo.SensorOffset
GROUP BY
WeatherStationId
)
SELECT
WS.Name
, SR.ReportedTime
, CASE WHEN SR.<reading> IS NOT NULL THEN SR.<reading> + SO.Offset ELSE NULL END AS <reading>
, <repeat same pattern as above for the various readings>
FROM dbo.WeatherStation WS
INNER JOIN dbo.SensorReading SR ON SR.WeatherStationId = WS.WeatherStationId
INNER JOIN CurrentOffset_CTE CO ON CO.WeatherStationId = WS.WeatherStationId
INNER JOIN dbo.SensorOffset SO ON SO.WeatherStationId = CO.WeatherStationId AND SO.Created = CO.CreatedContext
StackExchange Database Administrators Q#112154, answer score: 3
Revisions (0)
No revisions yet.