Time range- Sql - sql

please help me with my problem. So, I have a table named 'RATES' which contains these columns:
id (int)
rate (money)
start_time (datetime)
end_time(datetime)
example data:
1 150 8:00am 6:00pm
2 200 6:00pm 4:00am
3 250 8:00am 4:00am (the next day)
What I have to do is to select all the id(s) to where a given time would fall.
e.g given time: 9:00 pm, the output should be 2,3
The problem is I got this time range between 8am to 4am the next day and I don't know what to do. Help, please! thanks in advance :D

Assuming that #Andriy M is correct:
Data never spans more than 24 hours
if end_time<=start_time then end_time belongs to the next day
then what you're looking for is this:
Declare #GivenTime DateTime
Set #GivenTime = '9:00 PM'
Select ID
From Rates
Where (Start_Time<End_Time And Start_Time<=#GivenTime And End_Time>=#GivenTime)
Or (Start_Time=End_Time And Start_Time=#GivenTime)
Or (Start_Time>End_Time And (Start_Time>=#GivenTime Or End_Time<=#GivenTime))

I don't really ever use MS SQL, but maybe this will help.
I was going to suggest something like this, but by the way you have your data set up, this would fail.
SELECT id FROM RATES
WHERE datepart(hh, start_time) <= 9 AND datepart(hh, end_time) >= 9;
You'll have you search using the actual date if you expect to get the correct data back.
SELECT id FROM RATES
WHERE start_time <= '2011-1-1 9:00' AND end_time >= '2011-1-1 9:00';
This may not be exactly correct, but it may help you look in the right direction.

I guess #gbn is not going to help you. I will try and fill in.
Given -- a table called timedata that has ranges only going over at most one day
WITH normalized AS
(
SELECT *
FROM timedata
WHERE datepart(day,start_time) = datepart(day,endtime)
UNION ALL
SELECT id, rate, start_time, dateadd(second,dateadd(day,datediff(day,0,end_time),0),-1) as end_time
FROM timedata
WHERE not (datepart(day,start_time) = datepart(day,endtime))
UNION ALL
SELECT id, rate,dateadd(day,datediff(day,0,end_time),0) as start_time, end_time
FROM timedata
WHERE not (datepart(day,start_time) = datepart(day,endtime))
)
SELECT *
FROM normalized
WHERE datepart(hour,start_time) < #inhour
AND datepart(hour,end_time) > #inhour
This makes use of a CTE and a trick to truncate datetime values. To understand this trick read this question and answer: Floor a date in SQL server
Here is an outline of what this query does:
Create a normalized table with each time span only going over one day by
Selecting all rows that occur on the same day.
Then for each entry that spans two days joining in
Selecting the starttime and one second before the next day as the end time for all that span.
and
Selecting 12am of the end_time date as the starttime and the end_time.
Finally you perform the select using the hour indicator on this normalized table.
If your ranges go over more than one day you would need to use a recursive CTE to get the same normalized table.

Related

How to split time into hourly slot using SQL (can use view,or stored proc or function)

Example I have data in table which has start date, end date and duration. I want to show hourly time slot.
logic:
Condition 1. If start date =9:00 and end date = 11:00 then show the date as
09:00-10:00
10:00-11:00
It should repeat 2 times and all related column data will also repeat 2 times.
this will continue if time slot is suppose 11:00- 14:00 then
11:00-12:00
12:00-13:00
13:00-14:00
It should repeat 3 times.
Condition 2: If start date is 9:30 and end date is 10:30 then
time should round up. i.e. start date should be 9:00 and end date should be 11:00
How can I achieve this in Sql Server?
I assume that your issue is getting multiple rows from one, rather than formatting the date/time values as a string.
For this, you can use a recursive CTE:
with cte as (
select startdate as thetime, t.*
from t
union all
select dateadd(hour, 1, cte.startdate), . . . -- rest of columns here
from cte
where cte.thetime < cte.enddate
)
select cte.*
from cte;
You can then format thetime however you like, including the hyphenated version in your question.
SQL Server has a default limit of 100 for recursion -- the number of rows produced. Your example only uses times, so this can't exceed 24 and is not an issue. However, it could be an issue in other circumstances in which case option (maxrecursion 0) can be added to the query.

How can I cross join the following query results with a table of dates

I am looking for a query which gives me the daily playing time. The start (first_date) and end date(last_update) are given as shown in the Table. The following query gives me the sum of playing time on given date. How can I extend it to get a table from first day to last day and plot the query data in it and show 0 on dates when no game is played.
SELECT startTime, SUM(duration) as sum
FROM myTable
WHERE startTime = endTime
GROUP BY startTime
To show date when no one play you will need create a table days with a date field day so you could do a left join. (100 years is only 36500 rows).
Using select Generate days from date range
This use store procedure in MSQL
I will assume if a play pass the midnight a new record begin. So I could simplify my code and remove the time from datetime field
SELECT d.day, SUM(duration) as sum
FROM
days d
left join myTable m
on CONVERT(date, m.starttime) = d.day
GROUP BY d.day
If I understand correctly, you could try:
SELECT SUM(duration) AS duration, date
FROM myTable
WHERE date <= 20140430
AND date => 20140401
GROUP BY date
This would get the total time played for each date between april 1 and april 30
As far as showing 0 for dates not in the table, I don't know.
Also, the table you posted doesn't show a duration column, but the query you posted does, so I went ahead and used it.

Custom Postgres function for term dates and times

Lets say I have a large table that just consists of three columns.
Integer id,
timestamp ts,
double value
If I wanted to get the values given a complicated date expression what is the best way to achieve that ?
For example if I wanted to get all the values at anytime on weekend days and only between 18:00 and 8:00 on weekdays and any time on school holidays for the year 2014.
Obviously some of these times are variable and so the solution should be dynamic. I was thinking
of storing a series of date intervals for things like school holidays in another table to check against. However, I would like to create a custom Postgres function to hide some of the complexity.
Does anyone know of similar code or have suggestions ?
Especially dealing with cases like the times above except on weekend logic ?
Thanks
With a holiday table
select *
from
t
left join
holiday on date_trunc('day', t.ts) = holiday.day
where
extract(dow from ts) in (0, 6) -- Weekend
or
(extract(hour from ts) >= 18 and extract(hour from ts) <= 8)
or
holiday.day is not null -- Holiday

SQL WHERE timestamp BETWEEN MIDNIGHT AND MIDNIGHT

For my website I must select all messages sent between midnight (the previous night) and midnight (the next night). Basically, it's a 24 hours range.
I don't know how to do that as I store the date in a timestamp format in my DB.For example, last message was posted on 2013-10-18 11:23:35.
What I want is all message posted between 2013-10-18 00:00:00 and 2013-10-18 23:59:59.
Is that possible, if yes, how could I do that ?
You can calculate the required time in T-SQL as :
-- for previous day mid night as start time
declare #start_datetime datetime,#end_datetime datetime
Select #start_datetime = DATEADD(d,0,DATEDIFF(d,0,GETDATE()))
-- for current day mid night as end time
Select #end_datetime = DATEADD(SS,86399,DATEDIFF(d,0,GETDATE()))
select #start_datetime, #end_datetime
and then use you column name to check whether it exists between these two values.
To find out what happened between DatetimeA and DatetimeB, the sql keyword between is not your friend. It generally causes one to miss records. This construct is better.
where YourDateTimeField >= StartDateTime
and YourDateTimeField < JustAfterTheEndDateTime
In your case, you can simplify it with
where YourDateTimeField >= DateA
and YourDateTimeField < TheDayAfterDateA

SQL - Query events data for current quarter

I have a course calendar events table as follows (showing only a few records for simplicity):
calendarItemID classID startDate startTime endTime
----------------------------------------------------------
1 1 2011-11-24 7pm 9pm
2 2 2011-11-02 7pm 9pm
3 1 2011-11-25 7pm 9pm
I need a query that returns courses for the UPCOMING QUARTER (not the current quarter). Is there a SQL function that can help and/or is this a case of working out the dates in the current quarter and seeing if StartDate fits within those dates. I'm looking for the most elegant way if possible.
Thanks in advance!
Paul
Straightforward, but slow approach :
WHERE DATEPART(qq,startDate) = DATEADD(qq, 1,GETDATE()) AND YEAR(startDate) =
YEAR(DATEADD(qq, 1,GETDATE()))
By slow I mean that even if you have an index on (startDate) it won't be used.
The better solution is to get start_date and end_date for the next quarter. I can see a number of ways to do so. For instance, you can create 2 scalar UDF that returns start_date and end_date respectively. You can also create 1 table-valued function that returns 1 row with 2 columns and then join it. Finally, you can just create a lookup table and manually enter start/end date for next couple of years.
Create a table called say Quarters with a useful ID say YYYYQQ, and a start and end date, then it's a simple join.