I have time durations:
11-09-2018 10:00 AM - 11-09-2018 12:00 PM
11-09-2018 4:00 PM - 11-09-2018 8:00 PM
I have a requirement to write a SQL query to derive the other remaining durations for the day 11-09-2018. My query output should be:
11-09-2018 12:00 AM - 11-09-2018 9:59 AM
11-09-2018 12:01 PM - 11-09-2018 3:59 PM
11-09-2018 08:01 PM - 11-09-2018 11:59 PM
please use this for your requirement as general, it is useful when you want to give any date OR datetime as input and want output as given above then you can use following query. Put any date or datetime(timestamp) in place of getdate() and you will get the required output.
PRINT CONVERT(VARCHAR,dateadd(hh,00,datediff(dd,0,GETDATE())),100) + ' - ' + CONVERT(VARCHAR,dateadd(mi,59,dateadd(hh,09,datediff(dd,0,GETDATE()))),100) +' '+ char(13) + char(10) + CONVERT(VARCHAR,dateadd(mi,01,dateadd(hh,12,datediff(dd,0,GETDATE()))),100) + ' - ' + CONVERT(VARCHAR,dateadd(mi,59,dateadd(hh,15,datediff(dd,0,GETDATE()))),100) +' '+ char(13) + char(10) + CONVERT(VARCHAR,dateadd(mi,01,dateadd(hh,20,datediff(dd,0,GETDATE()))),100) + ' - ' + CONVERT(VARCHAR,dateadd(mi,59,dateadd(hh,23,datediff(dd,0,GETDATE()))),100)
Since you haven't provided DDL, I won't write a query, but I will give you an approach you can use.
You need to do some kind of UNION to account for the fact that you may need to create rows both before your first row AND after your last row.
One way you can do it is a "generate a row before each existing row, UNIONed with a last row"
Using a self-join (OUTER) to get a reference to the previous row, SELECT one minute after the previous row's end time as the start time (COALESCE NULL with '12 AM'), and one minute before the current row's start time as the end time. Use a WHERE clause to filter out any row with a start time of '12:00 AM'.
This will give you, for each row in your table, the time range before it that you want.
Then you UNION that with a final row, consisting of one minute after the last end time as the start time and '11:59 PM' as the end time. Use a WHERE clause to filter this row out if the last end time is '11:59 PM'.
Related
I have a column which has values in string type like below:
31-Oct-2016 12:00 AM
31-May-2015 12:00 PM
I want to convert the above column values to timestamp in IMPALA. Tried with cast, to_timestamp and other ways , but it is either showing syntax error or Null as result.
Can you please suggest a solution
2nd Requirement
There is a column like below in string, I want it to be converted to timestamp alone.
31-Oct-2016 12:00
31-May-2015 12:00
please suggest a way, I'm new to Impala
Thanks in advance
You can use below code. Unfortunately, impala doesn't have am pm conversion capability, but you can use a little code to identify PM and add 12 hours to that to convert properly.
select
if (right('31-Oct-2016 02:09 PM',2)='PM',
to_timestamp('31-Oct-2016 02:09 PM','d-MMM-yyyy H:m') + interval 12 hours,
to_timestamp('31-Oct-2016 02:09 PM','d-MMM-yyyy H:m')
) ampm_timestamp
Second requirement -
Impala always expects 24hour hour format when it converts datetime. So, in your case for 12 AM scenario, we have to do some special logic like below.
First check if its 12 AM, then minus 12 hours, else check if its PM, then add 12 hours(which covers 12PM scenario) and finally if its any other AM, it simply converts to timestamp.
select
CASE WHEN right('31-Oct-2016 12:09 AM',2)='AM' AND RIGHT( SPLIT_PART('31-Oct-2016 12:09 AM',':',1),2)='12'
THEN to_timestamp('31-Oct-2016 12:09 AM','d-MMM-yyyy HH:mm') - interval 12 HOURS
ELSE CASE WHEN right('31-Oct-2016 12:09 AM',2)='PM'
THEN to_timestamp('31-Oct-2016 12:09 AM','d-MMM-yyyy HH:mm') + interval 12 HOURS
ELSE to_timestamp('31-Oct-2016 12:09 AM','d-MMM-yyyy HH:mm')
END END AMPM_TIMESTAMP
Using date range to select values, but also need to use an hour range to determine if a record should be selected. The date ranges and time ranges are not necessarily associated.
game_time (between 6 am and 6 pm)
have tried straight between statement and datepart, but cannot get anything to capture what we need.
create table gametime(name varchar, start_time datetime, end_time datetime)
insert assorted name, start_times and end_times
Desired results
name start_time end_time
name1 8:00 AM 10:00 AM
name2 8:00 AM 11:30 AM
name3 4:00 PM 5:30 PM
name4 6:00 PM 9:00 PM
datetime is used is storage, but not needed in presentation.. only times are needed in presentation.
Selected games should only start between the hours of 6:00 AM and 6:00 PM.
Any and all suggestions and insight appreciated......
Using
LTRIM(RIGHT(CONVERT(VARCHAR(20), start_time, 100), 7))
to get the correct format for presentation,
but when I try to use
LTRIM(RIGHT(CONVERT(VARCHAR(20), start_time, 100), 7)) > 6
I get conversion errors.
I would use DATEPART rather than relying on converting to/comparing strings:
WHERE DATEPART(hour,start_time) BETWEEN 6 AND 18
Try CONVERT(VARCHAR(5),start_time,108) BETWEEN '06:00' AND '18:00'. Right now you're trying to compare a string to an integer.
Here's another way, provided you're on SQL Server 2008 or higher and have the TIME type available:
SELECT *
FROM gametime
WHERE CAST(start_time AS TIME) BETWEEN '06:00:00' and '18:00:00'
This can be a bit more flexible when your time range is not anchored to exact hours. It also is sarg-able -- i.e. it will use an index, where calling DATEPART will prevent that.
Im having a problem with derived columns in SSIS. When in SSMS i can set a column to have a default value using the following code:
(dateadd(month,datediff(month,(0),getdate())-(1),(0)))
and when data is entered into the database it will give it the timestamp of the previous month in the following format for example:
2010-09-01 00:00:00.000
This strangely is what im looking for and trying to duplicate/produce similar using the Derived Column DFT.
So far i have:
DATEADD("mm",DATEDIFF("mm",GETDATE(),GETDATE()) - 1,GETDATE())
which produces the month succesfully but the GETDATE() is not a correct replacement for the 0's in the original code.
Does the 0's in the original code signify the start date in SQL?
Any help would be much appreciated.
Regards,
Lee
your first code fragment is "flooring" the datetime to the month (making the date the 1st of the given month with no time) the "-1" makes it the previous month. All the extra unnecessary parenthesis in this code fragment give me a headache, here is the equivalent:
dateadd(month,datediff(month,0,getdate())-1,0)
This is how to floor a datetime to different units:
--Floor a datetime
DECLARE #datetime datetime;
SET #datetime = '2008-09-17 12:56:53.430';
SELECT '0 None', #datetime -- none 2008-09-17 12:56:53.430
UNION SELECT '1 Second',DATEADD(second,DATEDIFF(second,'2000-01-01',#datetime),'2000-01-01') -- Second: 2008-09-17 12:56:53.000
UNION SELECT '2 Minute',DATEADD(minute,DATEDIFF(minute,0,#datetime),0) -- Minute: 2008-09-17 12:56:00.000
UNION SELECT '3 Hour', DATEADD(hour,DATEDIFF(hour,0,#datetime),0) -- Hour: 2008-09-17 12:00:00.000
UNION SELECT '4 Day', DATEADD(day,DATEDIFF(day,0,#datetime),0) -- Day: 2008-09-17 00:00:00.000
UNION SELECT '5 Month', DATEADD(month,DATEDIFF(month,0,#datetime),0) -- Month: 2008-09-01 00:00:00.000
UNION SELECT '6 Year', DATEADD(year,DATEDIFF(year,0,#datetime),0) -- Year: 2008-01-01 00:00:00.000
ORDER BY 1
PRINT' '
PRINT 'Note that when you are flooring by the second, you will often get an arithmetic overflow if you use 0. So pick a known value that is guaranteed to be lower than the datetime you are attempting to floor'
PRINT 'this always uses a date less than the given date, so there will be no arithmetic overflow'
SELECT '1 Second',DATEADD(second,DATEDIFF(second,DATEADD(day,DATEDIFF(day,0,#datetime),0)-1,#datetime),DATEADD(day,DATEDIFF(day,0,#datetime),0)-1) -- Second: 2008-09-17 12:56:53.000
the second code fragment will not properly floor the datetime to the month, it will only move the date to the previous month and use the same day and time as the given datetime.
Beyond that I'm not sure what you are really asking.
here is a breakdown of what is happening in the OP's first code fragment:
select convert(datetime,0),'first datetime "0"'
select datediff(month,0,getdate()), 'months difference between the first datetime (1900-01-01) and given "getdate()"'
select datediff(month,0,getdate())-1, 'months difference between the first datetime (1900-01-01) and month previous to given "getdate()"'
select dateadd(month,datediff(month,0,getdate())-1,0), 'takes the first datetime (1900-01-01) and adds 1328 months onto that'
OUTPUT:
----------------------- ------------------
1900-01-01 00:00:00.000 first datetime "0"
----------- --------------------------------------------------------------------------------
1329 months difference between the first datetime (1900-01-01) and given "getdate()"
----------- --------------------------------------------------------------------------------------------------
1328 months difference between the first datetime (1900-01-01) and month previous to given "getdate()"
----------------------- --------------------------------------------------------------------
2010-09-01 00:00:00.000 takes the first datetime (1900-01-01) and adds 1328 months onto that
Here's what I think you may be looking for. It is an SSIS expression that gets the first day of the previous month for a given day (GETDATE() in the example).
DATEADD("mm",DATEDIFF("mm", (DT_DBTIMESTAMP)2, GETDATE()) - 1, (DT_DBTIMESTAMP)2)
I tried to simulate your SQL version of the expression, which determined the number of months between the 0 datetime and the current datetime. And, then it added the number of months to the 0 datetime.
It's not too important what the 0 datetime is, except that you wanted the 1st day of the month. In SQL the 0 datetime is 1900-01-01 00:00:00.000, so adding months automatically gives you the first day of the month. In SSIS expressions, the 0 datetime is 1899-12-30 00:00:00.000. Since you want the first day of a month, the expression above refers to the 2 datetime. So, in the expression (DT_DBTIMESTAMP)2 casts the number 2 to 1900-01-01 00:00:00.000.
month,0 makes it round down to the beginning of the month.
Can't you use your first expression if it does what you want? Or use the second expression but switch the two GETDATE()s you've added to 0. Do you get an error if you try that?
I think what you need in your derived column is this synatx:
DATEADD("mm",-1,(DT_DBTIMESTAMP)((DT_WSTR,4)DATEPART("YYYY",GETDATE()) + "-" + (DT_WSTR,2)DATEPART("mm",GETDATE()) + "-01"))
I have a table called TimeList
SlotID SlotStartTime SlotEndTime
(int identity) (varchar(10)) (varchar(10))
1 8:00AM 8:15AM
2 8:15AM 8:30AM
3 8:30AM 8:45AM
4 8:45AM 9:00AM
5 9:00AM 9:15AM
6 9:15AM 9:30AM
7 9:30AM 9:45AM
8 9:45AM 10:00AM
If I am passing SlotStartTime and SlotEndTime I want to get times in between.
I used the following query to get timeslots in b/w slotStarttime 8:00AM amd slotEndTime 9:00AM
select * from TimeList1 where StartTime >='8:00AM' and EndTime <= '9:00AM'
Here the result is coming as:
SlotID SlotStartTime SlotEndTime
1 8:00AM 8:15AM
2 8:15AM 8:30AM
3 8:30AM 8:45AM
8 9:45AM 10:00AM
I want to get slotstarttime starting from 8:00AM and slotendtime ending 9:00AM means
expected result is:
SlotID SlotStartTime SlotEndTime
1 8:00AM 8:15AM
2 8:15AM 8:30AM
3 8:30AM 8:45AM
4 8:45AM 9:00AM
What change do I have to make in my query to get the result as above?
When you're using varchars (or strings in most languages), you'll find that "10:00" < "9:00" just because of character sequencing rules (since "1" < "9").
You should be storing date and time values in date and time columns. If you must use varchars, you'll need to convert them to fixed-size 24-hour format to do it properly (e.g., "01:30", "12:15", "18:25").
But my advice is to store them as proper DB date and time values. Your queries will be easier and faster.
The following solution may get you what you want if I understand your data storage (one entry per quarter hour) but my professional opinion is to fix the column types, since that will allow for far more expressive conditions in your select statements:
select * from TimeList1
where left(StartTime,1) = '8'
and right(StartTime,2) = 'AM'
Part of the problem, as has been noted, is that you are using strings to represent times. The other part of your problem is that the AM/PM notation is completely ghastly for computational purposes. Remember, the sequence is:
12:00AM
12:15AM
12:30AM
12:45AM
1:00AM
1:15AM
...
9:45AM
10:00AM
10:15AM
...
11:30AM
11:45AM
12:00PM
12:15PM
12:30PM
12:45PM
1:00PM
1:15PM
...
The 24-hour clock has many merits. If you used:
00:00
00:15
00:30
00:45
01:00
01:15
...
09:45
10:00
10:15
...
11:30
11:45
12:00
12:15
12:30
12:45
13:00
13:15
...
(for the same set of numbers) then your VARCHAR strings could be made into CHAR(5) and would automatically sort correctly in time sequence. You would still have to phrase your queries correctly, including the leading zero(es) on times less than 10:00, but the values would sort correctly and compare correctly.
Some DBMS provide support for sub-sets of time. In IBM Informix Dynamic Server, you could use DATETIME HOUR TO MINUTE as the type for the column. That would give you back the flexibility of dropping leading zeroes.
See also Convert 12-hour date/time to 24-hour date/time.
Your query is correct. But it's your data types that are wrong.
10:00AM indeed comes before 9:00AM considering they are string, not datetime values.
So if you can't change the data types now, your best luck is to try this query :
Select * from TimeList1
where StartTime >= Cast('8:00AM' as datetime)
and EndTime <= Cast('9:00AM' as datetime)
//make sure StartTime and EndTime is type of datetime
Try this:
SELECT *
FROM TimeList1
WHERE (CONVERT(datetime, CONVERT(varchar, GETDATE(), 103) + ' ' + StartTime) >=
CONVERT(datetime, CONVERT(varchar, GETDATE(), 103) + ' ' + '8:00AM'))
AND
(CONVERT(datetime, CONVERT(varchar, GETDATE(), 103) + ' ' + EndTime) <=
CONVERT(datetime, CONVERT(varchar, GETDATE(), 103) + ' ' + '9:00AM'))
select *
from TimeList1
where StartTime >= '8:00AM'
and EndTime <= '9:00AM'
Less than or equal, not greater than or equal.
Though really, that doesn't work like you expect when your columns are of type varchar. Use a time or datetime type.
The first two paragraphs don't explain a thing as far as I can see. The last paragraph contains a flimsy explanation of the problem. – Jonathan Leffler
In the original post, before you edited it, the OP had as his select statement,
select *
from TimeList1
where StartTime >= '8:00AM'
and EndTime >= '9:00AM'
I was responding to that.
My response may be "flimsy", but I wanted to address the obvious problem and get the guy moving forward.
I am trying to find a way to have a SELECT statement return the set of dates between 2 input dates with a given interval. I would like to be able to easily change the time frame and interval that would be returned, so hard coding something with a series of SELECT ... UNIONs would not be ideal.
For example: I want all the dates at 5 second intervals for the last 60 seconds.
Expected:
times
---------------------
2009-02-05 08:00:00
2009-02-05 08:00:05
2009-02-05 08:00:10
2009-02-05 08:00:15
2009-02-05 08:00:20
...
2009-02-05 08:00:55
Edit:
generate_series(...) can be used in place of a table in the SELECT and simulates a table with a series of numbers in it with a given start value, end value and optionally a step. From there it can be CAST to the type I need for time functions and manipulated during the SELECT.
Thanks Quassnoi.
SELECT CAST (s || ' seconds' AS INTERVAL) + TIMESTAMP 'now'
FROM generate_series(0, -60, -5) s