Hi I have a weather database in SQL Server 2008 that is filled with weather observations that are taken every 20 minutes. I want to get the weather records for each hour not every 20 minutes how can I filter out some the results so only the first observation for each hour is in the results.
Example:
7:00:00
7:20:00
7:40:00
8:00:00
Desired Output
7:00:00
8:00:00
To get exactly (less the fact that it's an INT instead of a TIME; nothing hard to fix) what you listed as your desired result,
SELECT DISTINCT DATEPART(HOUR, TimeStamp)
FROM Observations
You could also add in CAST(TimeStamp AS DATE) if you wanted that as well.
Assuming you want the data as well, however, it depends a little, but from exactly what you've described, the simple solution is just to say:
SELECT *
FROM Observations
WHERE DATEPART(MINUTE, TimeStamp) = 0
That fails if you have missing data, though, which is pretty common.
If you do have some hours where you want data but don't have a row at :00, you could do something like this:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY CAST(TimeStamp AS DATE), DATEPART(HOUR, TimeStamp) ORDER BY TimeStamp)
FROM Observations
)
SELECT *
FROM cte
WHERE n = 1
That'll take the first one for any date/hour combination.
Of course, you're still leaving out anything where you had no data for an entire hour. That would require a numbers table, if you even want to return those instances.
You can use a formula like the following one to get the nearest hour of a time point (in this case it's GETUTCDATE()).
SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, 0, GETUTCDATE()) / 60 * 60, 0)
Then you can use this formula in the WHERE clause of your SQL query to get the data you want.
What you need is to GROUP BY your desired time frame, like the date and the hours. Then, you get the MIN value of the timeframe. Since you didn't specify which columns you are using, this is the most generic thing i can give.
Use as filter :
... where DATEPART(MINUTE, DateColumn) = 0
To filter the result for every whole hour, you can set your where clause to check for 00 minute since every whole hour is HH:00:00.
To get the minute part from a time-stamp, you can use DATEPART function.
SELECT *
FROM YOURTABLENAME
WHERE DATEPART(MINUTE, YOURDATEFIELDNAME) = 0
More information on datepart function can be found here: http://www.w3schools.com/sql/func_datepart.asp
Related
Trying to use the statement:
SELECT *
FROM data.example
WHERE TIMESTAMP(timeCollected) < DATE_ADD(USEC_TO_TIMESTAMP(NOW()), 60, 'MINUTE')
to get data from my bigquery data. It seems to return same set of result even when time is not within the range. timeCollected is of the format 2015-10-29 16:05:06.
I'm trying to build a query that is meant to return is data that is not older than an hour. So data collected within the last hour should be returned, the rest should be ignored.
Using Standard SQL:
SELECT * FROM data
WHERE timestamp > TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -60 MINUTE)
The query you made means "return to me anything that has a collection time smaller than an hour in the future" which will literally mean your whole table. You want the following (from what I got through your comment, at least) :
SELECT *
FROM data.example
WHERE TIMESTAMP(timeCollected) > DATE_ADD(USEC_TO_TIMESTAMP(NOW()), -60, 'MINUTE')
This means that any timeCollected that is NOT greater than an hour ago will not be returned. I believe this is what you want.
Also, unless you need it, Select * is not ideal in BigQuery. Since the data is saved by column, you can save money by selecting only what you need down the line. I don't know your use case, so * may be warranted though
To get table data collected within the last hour:
SELECT * FROM [data.example#-3600000--1]
https://cloud.google.com/bigquery/table-decorators
Using Standard SQL:
SELECT * FROM data WHERE timestamp > **TIMESTAMP_SUB**(CURRENT_TIMESTAMP(), INTERVAL 60 MINUTE)
I have a table that stores time, heart_rate, and player_id. I need to somehow take an average of the heart rate data over the last five minutes and group each average by the player ID.
Another option is to use DATEDIFF
SELECT AVG(heart_rate) AS heart_rate,
player_id
FROM tablename
WHERE DATEDIFF(MINUTE, time, GETDATE()) < 5
GROUP BY player_id
This is partly a response to Donal's answer (and too long for a comment).
You do not want to use the following:
WHERE datepart(minute, (time - GETDATE())) < 5
There are two reasons. First, this cannot make use of an index on time. That is, the calculation is not sargable. Second, the subtraction is backwards, unless time values are in the future.
A better way to write this is:
select player_id, avg(heart_rate)
from table t
where time >= dateadd(minute, -5, getdate())
group by player_id;
Suppose I have the following query:
select customer_name, origination_date
where origination_date < '01-DEC-2013';
I would like to select all customers that have an origination date older than 30 days. Is there a way in SQL (oracle, if specifics needed) to specify it in a more dynamic approach than manually entering the date so that I don't need to update the query every time I run it?
Thanks!
Sure try something like this:
select customer_name, origination_date where
origination_date >= DATEADD(day, -30, GETUTCDATE());
This basically says where the origination_date is greater or equal to 30 days from now. This works in Microsoft SQL, not sure but there is probably a similar function on Oracle.
in Oracle, when you subtract dates, by default you get the difference in days, e.g.
select * from my_table where (date_1 - date_2) > 30
should return the records whose date difference is greater than 30 days.
To make your query dynamic, you parameterize it, so instead of using hard coded date values, you use:
select * from my_table where (:date_1 - :date_2) > :threshold
If you are using oracle sql developer to run such a query, it will pop up a window for you to specify the values for your paramteres; the ones preceded with colon.
I have the table below
2012-05-24 19:00:00.000
2012-07-27 15:51:18.750
2012-07-30 09:40:25.333
2012-07-30 14:25:27.563
2012-07-27 15:51:18.750
2012-07-30 09:40:25.333
2012-07-30 14:25:27.563
2012-05-12 09:23:16.850
2012-05-12 18:00:00.000
I am trying to do a range select, so for example
SELECT * FROM RUN WHERE RUN_DATETIME = '14:25:29.563'
This is a very simple select, but my problem is that the date I am searching code be up too 30 seconds out from what is in the table above, so I need to be able to do the same as above but with a 30 second window and I am not sure what the best way to do this is.
This select is not based on another row, just the rows RUN_DATE within the window.
I am using SQL server 2008 R2
SELECT * FROM RUN
WHERE RUN_DATETIME < DATEDADD(s, '14:25:29.563', 30) AND
RUN_DATETIME > DATEDADD(s, '14:25:29.563', -30)
More complicated looking than podiluska's answer, but this works with indexes by pre-calculating the range.
SELECT *
FROM RUN
WHERE ABS(DATEDIFF(s, RUN_DATETIME , '14:25:29.563' ))< 30
SELECT
*
FROM
RUN
WHERE
RUN_DATETIME >= DATEADD(second, -30, '14:25:29.563')
AND RUN_DATETIME < DATEADD(second, 30, '14:25:29.563')
This is longer than the ABS(DATEDIFF()) version. It is, however, much faster when applied to indexed fields.
That is because the optimiser can easily see that you want all records within one sequential block. It can search for the start, then search for the end, and return everything between.
The ABS(DATEDIFF()) variation requires every row to be checked independantly, and makes no use of indexes or range seeks. It's a full scan of the whole table.
EDIT:
Also note that I use >= and <. This is standard practice for ranges of time.
For example val >= 0 AND val < 60 and val >= 60 AND val < 120 ensures that the value at val = 60 is only counted in one range of time.
I think RUN_DateTime column contains Date and comparison we are doing is with only Time here '14:25:29.563'. I agree with podiluska's answer. Just we would need to convert '14:25:29.563' to a date by taking out Day, month, year from RUN_DateTime column. We can do it by Date_Part function.
I am working on a sql view that should get the average number of hits by hour of the day, regardless of what day/date it is for traffic monitoring (12:00:00.000 - 12:59:59.999). Any ideas?
EDIT
Now I have the total, how do I get the average? SELECT AVG("FUNCTION BELOW") DOES NOT WORK
SELECT COUNT(*) AS total, DATEPART(hh, LogDate) AS HourOfDay
FROM dbo.Log
GROUP BY DATEPART(hh, LogDate)
Convert to DATEPART(hh,.....
Example SELECT DATEPART(hh,GETDATE())
Since you are on SQL Server 2008, you can use the time data type, just convert to time
example
SELECT CONVERT(TIME,GETDATE())
Then you can filter that also
Since I am not sure what your output is supposed to be like I am showing you both, but if all you need is to group by hour, then just do a datepart(hh.....
The query below may be good enough for you. It divides the count by the difference between todays date and the minimum date in the LogDate column.
SELECT DATEPART(hh,LogDate) as Hour
,CAST(COUNT(*)as decimal)/DATEDIFF(d,(SELECT MIN(LogDate) from log)
,CURRENT_TIMESTAMP) as AverageHits
, COUNT(*) as Count
FROM log
GROUP BY DATEPART(hh,LogDate)
ORDER by DATEPART(hh,LogDate) asc