SQL Total time based on Timestamp and States - sql

I have a table like this:
Timestamp | State
01-jan-2016 00:01:00 | ON
01-jan-2016 00:02:00 | OFF
01-jan-2016 00:02:01 | ON
01-jan-2016 00:03:00 | OFF
A Sample result would look like, considering NOW is 01-Jan-2016 00:03:10.
State | TotalTime
ON | 00:01:59
OFF | 00:00:11
I'd like to have a query that returns the total time [in hours, mins and secs] for each of the states. Is that possible using SQL Server Express 2012? Any ideas/directions I should take?

A small change would be required if you want to see over 24 hours
Declare #YourTable table (Timestamp datetime,State varchar(25))
Insert Into #YourTable values
('01-jan-2016 00:01:00','ON'),
('01-jan-2016 00:02:00','OFF'),
('01-jan-2016 00:02:01','ON'),
('01-jan-2016 00:03:00','OFF')
Declare #Default DateTime ='01-Jan-2016 00:03:10'
;with cteBase as (
Select *,NextTime = Lead(TimeStamp,1,#Default) over (Order By TimeStamp)
From #YourTable
)
Select State
,Duration=cast(DateAdd(SECOND,sum(DateDiff(SECOND,TimeStamp,NextTime)),cast('1900-01-01 00:00:00' as datetime)) as time)
From cteBase
Group By State
Returns
State Duration
OFF 00:00:11
ON 00:01:59
Just a quick note.
Lead(TimeStamp,1,TimeStamp) could be Lead(TimeStamp,1,GetDate()) if you want final state to current.

Related

Average over intersect

I've got this data set where I'm creating a report per shift displaying a certain activity per hour. Eg.: A shift runs from 7-15, so the report will be:
7:00 - 15 moves
8:00 - 18 moves
This report contains filters for weeks and days, as the goal is for users to see their shift performance.
However, I'd like to compare the activities in a specific hour with the same hour, same day in the last 10 weeks. So for example:
I've got 15 moves in hour 7:00 of a Tuesday and i'd like to compare that with the average move count on 7:00 of a Tuesday in the last 10 weeks.
How would I get this in SQL! :-)
Here is something that might get you moving in the right direction. Given that you have not stated your data structure, I have taken the liberty to assume what that may be.
You can run the following in SSMS to review/modify the results yourself.
First, I created a table variable to simulate the assumed data.
-- Create a dummy "shift" table --
DECLARE #shifts TABLE ( shift_id INT IDENTITY ( 1, 1 ) PRIMARY KEY, shift_date DATETIME, shift_moves INT );
Then I inserted some dummy data. For the sake of time and simplicity, I stuck with Tuesdays over the last ten weeks.
-- Insert ten weeks of Tuesdays --
INSERT INTO #shifts ( shift_date, shift_moves ) VALUES
( '11/06/2018 07:10:00', 5 )
, ( '11/13/2018 07:08:00', 12 )
, ( '11/20/2018 07:00:00', 14 )
, ( '11/27/2018 07:20:00', 15 )
, ( '12/04/2018 07:35:00', 12 )
, ( '12/11/2018 07:18:00', 11 )
, ( '12/18/2018 07:16:00', 10 )
, ( '12/25/2018 07:00:00', 12 )
, ( '01/01/2019 07:00:00', 13 )
, ( '01/08/2019 07:22:00', 15 );
The table variable #shifts now contains the following data:
+----------+-------------------------+-------------+
| shift_id | shift_date | shift_moves |
+----------+-------------------------+-------------+
| 1 | 2018-11-06 07:10:00.000 | 5 |
| 2 | 2018-11-13 07:08:00.000 | 12 |
| 3 | 2018-11-20 07:00:00.000 | 14 |
| 4 | 2018-11-27 07:20:00.000 | 15 |
| 5 | 2018-12-04 07:35:00.000 | 12 |
| 6 | 2018-12-11 07:18:00.000 | 11 |
| 7 | 2018-12-18 07:16:00.000 | 10 |
| 8 | 2018-12-25 07:00:00.000 | 12 |
| 9 | 2019-01-01 07:00:00.000 | 13 |
| 10 | 2019-01-08 07:22:00.000 | 15 |
+----------+-------------------------+-------------+
I created a few parameters that you might pass to a stored procedure.
-- What date are we looking at? --
DECLARE #date DATETIME = '01/08/2019';
-- How many weeks back to compare? --
DECLARE #weeks_back INT = -10;
*Remember: To look backward, #weeks_back MUST be a negative number. In production, you would have a check/handle for this.
Next, I created two local variables to help keep the date/time simple for use when querying.
-- Create variables for the start and end times for simplicity --
DECLARE
#sDT DATETIME = CAST( CONVERT( VARCHAR(10), #date, 101 ) + ' 00:00:00' AS DATETIME ),
#eDT DATETIME = CAST( CONVERT( VARCHAR(10), #date, 101 ) + ' 23:59:59' AS DATETIME );
Then, it was a matter of querying the data for the desired results using CROSS APPLY.
Using CROSS APPLY allows me to query a second subset of shift data that is tied to the primary record queried ( in this case a shift_date of 01/08/2019 ) for the desired time frame ( #weeks_back ).
-- Get resultset --
SELECT
DATEPART( hh, shift_date ) AS [shift_hour]
, DATENAME( dw, s.shift_date ) AS [shift_day]
, CONVERT( VARCHAR(10), s.shift_date, 101 ) AS [shift_date]
, s.shift_moves
, shift_avg.shift_average
FROM #shifts AS s
CROSS APPLY (
SELECT
AVG( a.shift_moves ) AS [shift_average]
FROM #shifts a
WHERE
-- restrict to the current hour.
DATEPART( HH, a.shift_date ) = DATEPART( HH, s.shift_date )
-- restrict to the current day of the week.
AND DATEPART( DW, a.shift_date ) = DATEPART( DW, s.shift_date )
-- compare against the desired time period / weeks back.
AND a.shift_date BETWEEN DATEADD( WW, #weeks_back, CAST( CONVERT( VARCHAR(10), s.shift_date, 101 ) AS DATETIME ) ) AND a.shift_date
) AS shift_avg
WHERE
s.shift_date BETWEEN #sDT AND #eDT
ORDER BY
s.shift_date;
Which returns the following resultset:
+------------+-----------+------------+-------------+---------------+
| shift_hour | shift_day | shift_date | shift_moves | shift_average |
+------------+-----------+------------+-------------+---------------+
| 7 | Tuesday | 01/08/2019 | 15 | 11 |
+------------+-----------+------------+-------------+---------------+
I hope this helps get you moving in the desired direction, #Aron.

How do I subtract two columns with datetime in SQLite?

I am learning SQLite for work and I am trying to subtract 'Enddate' column fromn 'Startdate' column, which contain date and time. Soemthing like this:
Startdate 3/15/18 16:00 3/28/18 17:00
Enddate 3/19/18 00:00 3/20/18 00:00
My table's name is data1. I tried this:
select *,
strftime('%m/%d/%y %H:%M', 'data1.Enddate') -
(strftime('%m/%d/%y %H:%M', 'data1.Startdate')) as TimeOff
from data1;
But this gives me all 'Null' values.
If you could help me with this I would really appreciate that. That you so much!
Two possible reasons you got NULL (likely because of a silent error):
1) Your dates are malformed when you create them. They should be yyyy-mm-dd HH:MM:SS format instead.
2) Not having a closing semicolon in one of your queries. I see it in the one above, but if the one where you insert your test rows didn't close properly, you may not
My test query:
https://dbfiddle.uk/?rdbms=sqlite_3.8&fiddle=8b9a168291bbc08c74a895ce22ab41ac
Setup
CREATE TABLE data1 (foo int, StartDate datetime, EndDate datetime) ;
INSERT INTO data1 (foo, StartDate, EndDate)
VALUES (1,'2018-03-15 16:00:00', '2018-03-28 17:00:00')
, (2,'2018-03-19 00:00:00', '2018-03-20 00:00:00') ;
The Query
SELECT foo, StartDate, EndDate
, julianday(EndDate)-julianday(StartDate) AS TimeOffInDays
, CAST((julianday(EndDate) - julianday(StartDate))*24 AS real) AS TimeOffInHours
FROM data1 ;
Which gives us...
| foo | StartDate | EndDate | TimeOffInDays | TimeOffInHours |
=========================================================================================
| 1 | 2018-03-15 16:00:00 | 2018-03-28 17:00:00 | 13.041666666977 | 313.00000000745 |
| 2 | 2018-03-19 00:00:00 | 2018-03-20 00:00:00 | 1 | 24 |

Discard existing dates that are included in the result, SQL Server

In my database I have a Reservation table and it has three columns Initial Day, Last Day and the House Id.
I want to count the total days and omit those who are repeated, for example:
+-------------+------------+------------+
| | Results | |
+-------------+------------+------------+
| House Id | InitialDay | LastDay |
+-------------+------------+------------+
| 1 | 2017-09-18 | 2017-09-20 |
| 1 | 2017-09-18 | 2017-09-22 |
| 19 | 2017-09-18 | 2017-09-22 |
| 20 | 2017-09-18 | 2017-09-22 |
+-------------+------------+------------+
If you noticed the House Id with the number 1 has two rows, and each row has dates but the first row is in the interval of dates of the second row. In total the number of days should be 5 because the first shouldn't be counted as those days already exist in the second.
The reason why this is happening is that each house has two rooms, and different persons can stay in that house on the same dates.
My question is: how can I omit those cases, and only count the real days the house was occupied?
In your are using SQL Server 2012 or higher you can use LAG() to get the previous final date and adjust the initial date:
with ReservationAdjusted as (
select *,
lag(LastDay) over(partition by HouseID order by InitialDay, LastDay) as PreviousLast
from Reservation
)
select HouseId,
sum(case when PreviousLast>LastDay then 0 -- fully contained in the previous reservation
when PreviousLast>=InitialDay then datediff(day,PreviousLast,LastDay) -- overlap
else datediff(day,InitialDay,LastDay)+1 -- no overlap
end) as Days
from ReservationAdjusted
group by HouseId
The cases are:
The reservation is fully included in the previous reservation: we only need to compare end dates because the previous row is obtained ordering by InitialDay, LastDay, so the previous start date is always minor or equal than the current start date.
The current reservation overlaps with the previous: in this case we adjust the start and don't add 1 (the initial day is already counted), this case include when the previous end is equal to the current start (is a one day overlap).
There is no overlap: we just calculate the difference and add 1 to count also the initial day.
Note that we don't need extra condition for the reservation of a HouseID because by default the LAG() function returns NULL when there isn't a previous row, and comparisons with null always are false.
Sample input and output:
| HouseId | InitialDay | LastDay |
|---------|------------|------------|
| 1 | 2017-09-18 | 2017-09-20 |
| 1 | 2017-09-18 | 2017-09-22 |
| 1 | 2017-09-21 | 2017-09-22 |
| 19 | 2017-09-18 | 2017-09-27 |
| 19 | 2017-09-24 | 2017-09-26 |
| 19 | 2017-09-29 | 2017-09-30 |
| 20 | 2017-09-19 | 2017-09-22 |
| 20 | 2017-09-22 | 2017-09-26 |
| 20 | 2017-09-24 | 2017-09-27 |
| HouseId | Days |
|---------|------|
| 1 | 5 |
| 19 | 12 |
| 20 | 9 |
select house_id,min(initialDay),max(LastDay)
group by houseId
If I understood correctly!
Try out and let me know how it works out for you.
Ted.
While thinking through your question I came across the wonder that is the idea of a Calendar table. You'd use this code to create one, with whatever range of dates your want for your calendar. Code is from http://blog.jontav.com/post/9380766884/calendar-tables-are-incredibly-useful-in-sql
declare #start_dt as date = '1/1/2010';
declare #end_dt as date = '1/1/2020';
declare #dates as table (
date_id date primary key,
date_year smallint,
date_month tinyint,
date_day tinyint,
weekday_id tinyint,
weekday_nm varchar(10),
month_nm varchar(10),
day_of_year smallint,
quarter_id tinyint,
first_day_of_month date,
last_day_of_month date,
start_dts datetime,
end_dts datetime
)
while #start_dt < #end_dt
begin
insert into #dates(
date_id, date_year, date_month, date_day,
weekday_id, weekday_nm, month_nm, day_of_year, quarter_id,
first_day_of_month, last_day_of_month,
start_dts, end_dts
)
values(
#start_dt, year(#start_dt), month(#start_dt), day(#start_dt),
datepart(weekday, #start_dt), datename(weekday, #start_dt), datename(month, #start_dt), datepart(dayofyear, #start_dt), datepart(quarter, #start_dt),
dateadd(day,-(day(#start_dt)-1),#start_dt), dateadd(day,-(day(dateadd(month,1,#start_dt))),dateadd(month,1,#start_dt)),
cast(#start_dt as datetime), dateadd(second,-1,cast(dateadd(day, 1, #start_dt) as datetime))
)
set #start_dt = dateadd(day, 1, #start_dt)
end
select *
into Calendar
from #dates
Once you have a calendar table your query is as simple as:
select distinct t.House_id, c.date_id
from Reservation as r
inner join Calendar as c
on
c.date_id >= r.InitialDay
and c.date_id <= r.LastDay
Which gives you a row for each unique day each room was occupied. If you need a sum of how many days each room was occupied it becomes:
select a.House_id, count(a.House_id) as Days_occupied
from
(select distinct t.House_id, c.date_id
from so_test as t
inner join Calendar as c
on
c.date_id >= t.InitialDay
and c.date_id <= t.LastDay) as a
group by a.House_id
Create a table of all the possible dates and then join it to the Reservations table so that you have a list of all days between InitialDay and LastDay. Like this:
DECLARE #i date
DECLARE #last date
CREATE TABLE #temp (Date date)
SELECT #i = MIN(Date) FROM Reservations
SELECT #last = MAX(Date) FROM Reservations
WHILE #i <= #last
BEGIN
INSERT INTO #temp VALUES(#i)
SET #i = DATEADD(day, 1, #i)
END
SELECT HouseID, COUNT(*) FROM
(
SELECT DISTINCT HouseID, Date FROM Reservation
LEFT JOIN #temp
ON Reservation.InitialDay <= #temp.Date
AND Reservation.LastDay >= #temp.Date
) AS a
GROUP BY HouseID
DROP TABLE #temp

How do I relate a table of events to a table of intervals?

I need to merge two tables based on overlapping time data, and I don't know how to do this in SQL. I have a table of events and times, such as this:
Event_Table
+----------------+-------+
| Event | Time |
+----------------+-------+
| Fire Alarm | 10:00 |
| Smoke Alarm | 13:00 |
| Security Alarm | 16:00 |
+----------------+-------+
I also have a table of time intervals, such as this:
Interval_Table
+--------+-------------+-----------+
| Warden | Shift_Start | Shift_End |
+--------+-------------+-----------+
| Jack | 09:00 | 10:30 |
| John | 14:00 | 20:00 |
+--------+-------------+-----------+
I need to make a table of events which includes which warden was on duty at the time:
Output_Table
+----------------+-------+----------------+
| Event | Time | Warden_On_Duty |
+----------------+-------+----------------+
| Fire Alarm | 10:00 | Jack |
| Smoke Alarm | 13:00 | [null] |
| Security Alarm | 16:00 | John |
+----------------+-------+----------------+
Some Warden shifts might overlap, but that should be ignored; maximum one warden name should be displayed for every event. The tables are very large (~500,000 rows). Any ideas on how this can be achieved with SQL?
Here is one way to do this. Notice how I posted consumable ddl and sample data? You should do this in the future. It makes it a LOT easier to help. Most of time on this was setting up the problem. The query itself was a trivial effort.
if OBJECT_ID('tempdb..#Event') is not null
drop table #Event
create table #Event
(
EventName varchar(20)
, EventTime time
)
insert #Event
select 'Fire Alarm', '10:00' union all
select 'Smoke Alarm', '13:00' union all
select 'Security Alarm', '16:00'
if OBJECT_ID('tempdb..#Shifts') is not null
drop table #Shifts
create table #Shifts
(
Warden varchar(10)
, StartTime time
, EndTime time
)
insert #Shifts
select 'Jack', '09:00', '10:30' union all
select 'John', '14:00', '20:00' union all
select 'overlap', '15:00', '22:00';
with SortedResults as
(
select *
, ROW_NUMBER() over (partition by e.EventName order by s.StartTime) as RowNum
from #Event e
join #Shifts s on s.StartTime <= e.EventTime and s.EndTime >= e.EventTime
)
select *
from SortedResults
where RowNum = 1
Try this:
select
Event,
Time,
(select top 1 Warden from Interval_Table where Time between Shift_Start and Shift_End) as Warden_On_Duty
from Event_Table

Is it possible to temporarily duplicate and modify rows on the fly in an SQL SELECT query?

I've just received a new data source for my application which inserts data into a Derby database only when it changes. Normally, missing data is fine - I'm drawing a line chart with the data (value over time), and I'd just draw a line between the two points, extrapolating the expected value at any given point. The problem is that as missing data in this case means "draw a straight line," the graph would be incorrect if I did this.
There are two ways I could fix this: I could create a new class that handles missing data differently (which could be difficult due to the way prefuse, the drawing library I'm using, handles drawing), or I could duplicate the rows, leaving the y value the same while changing the x value in each row. I could do this in the Java that bridges the database and the renderer, or I could modify the SQL.
My question is, given a result set like the one below:
+-------+---------------------+
| value | received |
+-------+---------------------+
| 7 | 2000-01-01 08:00:00 |
| 10 | 2000-01-01 08:00:05 |
| 11 | 2000-01-01 08:00:07 |
| 2 | 2000-01-01 08:00:13 |
| 4 | 2000-01-01 08:00:16 |
+-------+---------------------+
Assuming I query it at 8:00:20, how can I make it look like the following using SQL? Basically, I'm duplicating the row for every second until it's already taken. received is, for all intents and purposes, unique (it's not, but it will be due to the WHERE clause in the query).
+-------+---------------------+
| value | received |
+-------+---------------------+
| 7 | 2000-01-01 08:00:00 |
| 7 | 2000-01-01 08:00:01 |
| 7 | 2000-01-01 08:00:02 |
| 7 | 2000-01-01 08:00:03 |
| 7 | 2000-01-01 08:00:04 |
| 10 | 2000-01-01 08:00:05 |
| 10 | 2000-01-01 08:00:06 |
| 11 | 2000-01-01 08:00:07 |
| 11 | 2000-01-01 08:00:08 |
| 11 | 2000-01-01 08:00:09 |
| 11 | 2000-01-01 08:00:10 |
| 11 | 2000-01-01 08:00:11 |
| 11 | 2000-01-01 08:00:12 |
| 2 | 2000-01-01 08:00:13 |
| 2 | 2000-01-01 08:00:14 |
| 2 | 2000-01-01 08:00:15 |
| 4 | 2000-01-01 08:00:16 |
| 4 | 2000-01-01 08:00:17 |
| 4 | 2000-01-01 08:00:18 |
| 4 | 2000-01-01 08:00:19 |
| 4 | 2000-01-01 08:00:20 |
+-------+---------------------+
Thanks for your help.
Due to the set based nature of SQL, there's no simple way to do this. I have used two solution strategies:
a) use a cycle to go from the initial to end date time and for each step get the value, and insert that into a temp table
b) generate a table (normal or temporary) with the 1 minute increments, adding the base date time to this table you can generate the steps.
Example of approach b) (SQL Server version)
Let's assume we will never query more than 24 hours of data. We create a table intervals that has a dttm field with the minute count for each step. That table must be populated previously.
select dateadd(minute,stepMinutes,'2000-01-01 08:00') received,
(select top 1 value from table where received <=
dateadd(minute,dttm,'2000-01-01 08:00')
order by received desc) value
from intervals
It seems like in this case you really don't need to generate all of these datapoints. Would it be correct to generate the following instead? If it's drawing a straight line, you don't need go generate a data point for each second, just two for each datapoint...one at the current time, one right before the next time. This example subtracts 5 ms from the next time, but you could make it a full second if you need it.
+-------+---------------------+
| value | received |
+-------+---------------------+
| 7 | 2000-01-01 08:00:00 |
| 7 | 2000-01-01 08:00:04 |
| 10 | 2000-01-01 08:00:05 |
| 10 | 2000-01-01 08:00:06 |
| 11 | 2000-01-01 08:00:07 |
| 11 | 2000-01-01 08:00:12 |
| 2 | 2000-01-01 08:00:13 |
| 2 | 2000-01-01 08:00:15 |
| 4 | 2000-01-01 08:00:16 |
| 4 | 2000-01-01 08:00:20D |
+-------+---------------------+
If that's the case, then you can do the following:
SELECT * FROM
(SELECT * from TimeTable as t1
UNION
SELECT t2.value, dateadd(ms, -5, t2.received)
from ( Select t3.value, (select top 1 t4.received
from TimeTable t4
where t4.received > t3.received
order by t4.received asc) as received
from TimeTable t3) as t2
UNION
SELECT top 1 t6.value, GETDATE()
from TimeTable t6
order by t6.received desc
) as t5
where received IS NOT NULL
order by t5.received
The big advantage of this is that it is a set based solution and will be much faster than any iterative approach.
You could just walk a cursor, keep vars for the last value & time returned, and if the current one is more than a second ahead, loop one second at a time using the previous value and the new time until you get the the current row's time.
Trying to do this in SQL would be painful, and if you went and created the missing data, you would possible have to add a column to track real / interpolated data points.
Better would be to have a table for each axial value you want to have on the graph, and then either join to it or even just put the data field there and update that record when/if values arrive.
The "missing values" problem is quite extensive, so I suggest you have a solid policy.
One thing that will happen is that you will have multiple adjacent slots with missing values.
This would be much easier if you could transform it into OLAP data.
Create a simple table that has all the minutes (warning, will run for a while):
Create Table Minutes(Value DateTime Not Null)
Go
Declare #D DateTime
Set #D = '1/1/2000'
While (Year(#D) < 2002)
Begin
Insert Into Minutes(Value) Values(#D)
Set #D = DateAdd(Minute, 1, #D)
End
Go
Create Clustered Index IX_Minutes On Minutes(Value)
Go
You can then use it somewhat like this:
Select
Received = Minutes.Value,
Value = (Select Top 1 Data.Value
From Data
Where Data.Received <= Minutes.Received
Order By Data.Received Desc)
From
Minutes
Where
Minutes.Value Between #Start And #End
I would recommend against solving this in SQL/the database due to the set based nature of it.
Also you are dealing with seconds here so I guess you could end up with a lot of rows, with the same repeated data, that would have to be transfered from the database to you application.
One way to handle this is to left join your data against a table that contains all of the received values. Then, when there is no value for that row, you calculate what the projected value should be based on the previous and next actual values you have.
You didn't say what database platform you are using. In SQL Server, I would create a User Defined Function that accepts a start datetime and end datetime value. It would return a table value with all of the received values you need.
I have simulated it below, which runs in SQL Server. The subselect aliased r is what would actually get returned by the user defined function.
select r.received,
isnull(d.value,(select top 1 data.value from data where data.received < r.received order by data.received desc)) as x
from (
select cast('2000-01-01 08:00:00' as datetime) received
union all
select cast('2000-01-01 08:00:01' as datetime)
union all
select cast('2000-01-01 08:00:02' as datetime)
union all
select cast('2000-01-01 08:00:03' as datetime)
union all
select cast('2000-01-01 08:00:04' as datetime)
union all
select cast('2000-01-01 08:00:05' as datetime)
union all
select cast('2000-01-01 08:00:06' as datetime)
union all
select cast('2000-01-01 08:00:07' as datetime)
union all
select cast('2000-01-01 08:00:08' as datetime)
union all
select cast('2000-01-01 08:00:09' as datetime)
union all
select cast('2000-01-01 08:00:10' as datetime)
union all
select cast('2000-01-01 08:00:11' as datetime)
union all
select cast('2000-01-01 08:00:12' as datetime)
union all
select cast('2000-01-01 08:00:13' as datetime)
union all
select cast('2000-01-01 08:00:14' as datetime)
union all
select cast('2000-01-01 08:00:15' as datetime)
union all
select cast('2000-01-01 08:00:16' as datetime)
union all
select cast('2000-01-01 08:00:17' as datetime)
union all
select cast('2000-01-01 08:00:18' as datetime)
union all
select cast('2000-01-01 08:00:19' as datetime)
union all
select cast('2000-01-01 08:00:20' as datetime)
) r
left outer join Data d on r.received = d.received
If you were in SQL Server, then this would be a good start. I am not sure how close Apache's Derby is to sql.
Usage: EXEC ElaboratedData '2000-01-01 08:00:00','2000-01-01 08:00:20'
CREATE PROCEDURE [dbo].[ElaboratedData]
#StartDate DATETIME,
#EndDate DATETIME
AS
--if not a valid interval, just quit
IF #EndDate<=#StartDate BEGIN
SELECT 0;
RETURN;
END;
/*
Store the value of 1 second locally, for readability
--*/
DECLARE #OneSecond FLOAT;
SET #OneSecond = (1.00000000/86400.00000000);
/*
create a temp table w/the same structure as the real table.
--*/
CREATE TABLE #SecondIntervals(TSTAMP DATETIME, DATAPT INT);
/*
For each second in the interval, check to see if we have a known value.
If we do, then use that. If not, make one up.
--*/
DECLARE #CurrentSecond DATETIME;
SET #CurrentSecond = #StartDate;
WHILE #CurrentSecond <= #EndDate BEGIN
DECLARE #KnownValue INT;
SELECT #KnownValue=DATAPT
FROM TESTME
WHERE TSTAMP = #CurrentSecond;
IF (0 = ISNULL(#KnownValue,0)) BEGIN
--ok, we have to make up a fake value
DECLARE #MadeUpValue INT;
/*
*******Put whatever logic you want to make up a fake value here
--*/
SET #MadeUpValue = 99;
INSERT INTO #SecondIntervals(
TSTAMP
,DATAPT
)
VALUES(
#CurrentSecond
,#MadeUpValue
);
END; --if we had to make up a value
SET #CurrentSecond = #CurrentSecond + #OneSecond;
END; --while looking thru our values
--finally, return our generated values + real values
SELECT TSTAMP, DATAPT FROM #SecondIntervals
UNION ALL
SELECT TSTAMP, DATAPT FROM TESTME
ORDER BY TSTAMP;
GO
As just an idea, you might want to check out Anthony Mollinaro's SQL Cookbook, chapter 9. He has a recipe, "Filling in Missing Dates" (check out pages 278-281), that discusses primarily what you are trying to do. It requires some sort of sequential handling, either via a helper table or doing the query recursively. While he doesn't have examples for Derby directly, I suspect you could probably adapt them to your problem (particularly the PostgreSQL or MySQL one, it seems somewhat platform agnostic).