I have a table with this schema:
DeviceID int
FloorID int
RoomID int
DateRecorded datetime
RecordedValue decimal
A sample of the table’s data looks like:
DeviceID FloorID RoomID DateRecorded RecordedValue 0001 Floor 1 Room 1 1/1/2000 0 0001 Floor 1 Room 1 1/2/2000 10.5000 0001 Floor 1 Room 1 1/3/2000 18.7500 0002 Floor 1 Room 2 1/1/2000 10.0000 0002 Floor 1 Room 2 1/2/2000 10.0000 0002 Floor 1 Room 2 1/3/2000 22.5000
I need to build a query that will give me the RecordedValue range each device recorded for each date.
Something like:
DeviceID FloorID RoomID DateRecorded StartValue EndValue 0001 Floor 1 Room 1 1/1/2000 NULL 0 0001 Floor 1 Room 1 1/2/2000 0.0001 10.5000 0001 Floor 1 Room 1 1/3/2000 10.5001 18.7500 0002 Floor 1 Room 2 1/1/2000 NULL 10.0000 0002 Floor 1 Room 2 1/2/2000 10.0000 10.0000 0002 Floor 1 Room 2 1/3/2000 10.0001 22.5000
So basically, it has to take the MIN from the previous day’s recording if exists or NULL and the MAX from the next day if exists or NULL.
Each device records the accumulated value each day.
Note the issue when the device records the same value for a few days… Also don’t assume that we get a reading every day. We may have gaps in the days recorded.
Advertisement
Answer
Your question isn’t entirely clear. You appear to be computing the start and end values from the previous day’s values according to some formula, but you don’t state what the formula is. for instance, it’s not clear to me why Dev 2 on 1/2/2000 has an end value of 22.4999 when the recorded value is 10.000.
Also, you don’t state whether each device is limited to a single record per day.
Assuming the following:
- Each device has only one reading per day.
- There is a reading every single date.
- The StartValue for day X is .0001 more than the EndValue for day X-1.
then you can use something like the following query:
SELECT D1.DeviceID, D1.FloorID, D1.RoomID, D1.DateRecorded, D2.RecordedValue + .0001 AS StartValue, D1.RecordedValue AS EndValue FROM YourTable D1 INNER JOIN YourTable D2 ON D1.DeviceID = D2.DeviceID AND D1.FloorID = D2.FloorID AND D1.RoomID = D2.RoomID AND D1.DateRecorded = D2.DateRecorded+1
This will problems with the first or last day in the data set. You can solve that problem by switching to a LEFT or RIGHT OUTER JOIN, depending on whether you want the first or last date to appear.
Also note that you should factor out FloorID and RoomID from your recorded values table since they appear to depend on DeviceID. This will normalize your database, reduce storage, and simply the JOIN conditions in the query.
Edit in response to comments, below:
If assumption #2 (there’s a record for every day) is not valid, then you can use something like this revised version (also changed not to use the .0001 to generate a false start value):
SELECT D1.DeviceID, D1.FloorID, D1.RoomID, D1.DateRecorded, D2.RecordedValue AS StartValue, D1.RecordedValue AS EndValue FROM YourTable D1 INNER JOIN YourTable D2 ON D1.DeviceID = D2.DeviceID AND D1.FloorID = D2.FloorID AND D1.RoomID = D2.RoomID AND D2.DateRecorded = (SELECT MAX(DateRecorded) FROM YourTable WHERE DeviceID = D1.DeviceID AND FloorID = D1.FloorID AND RoomID = D1.RoomID AND DateRecorded < D1.DateRecorded)
And I’ll just rewrite this to show you how much smaller it is if you factor out the non-normalized columns:
SELECT D1.DeviceID, D1.FloorID, D1.RoomID, D1.DateRecorded, D2.RecordedValue AS StartValue, D1.RecordedValue AS EndValue FROM YourTable D1 INNER JOIN YourTable D2 ON D1.DeviceID = D2.DeviceID AND D2.DateRecorded = (SELECT MAX(DateRecorded) FROM YourTable WHERE DeviceID = D1.DeviceID AND DateRecorded < D1.DateRecorded)