Sql query to get range of values - sql-server-2005

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.

Related

Convert String column which has AM/PM to Timestamp in Impala

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

T-SQL : convert(datetime) to include/exclude certain hours

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.

Convert Seconds to Hours and Minutes

I have read all the posts on StackOverflow about converting an integer from seconds to hours and minutes. I am using this statement to achieve the results below:
SELECT EventDate, OriginalSeconds,
LEFT(CONVERT(VARCHAR(5),
DATEADD(second, OriginalSeconds, 0), 108), 5)
I get the following result:
EventDate Seconds Converted Time SHOULD BE
01/13/2011 4860001 06:00 13:30
01/13/2011 4860001 06:00 13:30
01/14/2013 3960001 20:00 11:00
02/03/2011 3960001 20:00 11:00
The only problem, of course, is that the converted Time column has not been calculated correctly. (I placed the correct result in the SHOULD BE column for your re:.)
I am imagining that it is because the seconds column actually has extraneous data at the end. But isn't the LEFT function fixing that?
The SHOULD BE column is what I would like to achieve. What am I doing wrong? I was looking for a simple solution without a function, but not sure I can achieve that.
The correct statement (using your code) is
SELECT EventDate, OriginalSeconds,
LEFT(CONVERT(VARCHAR(5),
DATEADD(second, OriginalSeconds/100, 0), 108), 5)
This gives 13:30 for 4860001
You needed to tell us what part of the original OriginalSeconds column wasn't seconds.
DATEADD(second, #secs/100, 0) turns 4860001 into 1900-01-01 13:30:00.000
CONVERT(VARCHAR(5), 1900-01-01 13:30:00.000, 108) turns it into 13:30
The Left Is probably not needed. I just tried it with 9000001 and got a result of 01:00. So the formula wraps to 24 hours

Converting SQL date formats not ending up the same

I am trying to remove the timestamp from my date values so I end up with something like mm/dd/yy or mm/dd/yyyy. I referenced many technet, stackoverflow, and w3schools articles but still can't get the date to appear correctly. All of my columns in the table are defined as a datetime and they come from the same table.
I am using convert statements like this: CONVERT(VARCHAR(10), E.PD_DT, 101) AS 'Paid Date'
In place of 101 I have used 10 and 11, still have the same issue with the data (below). What's happening is when the date value (not including the time) is 8 characters, I am getting an additional character from the time, as seen in the Claim Adjustment Date-10 and Claim Adjustment Date-11 columns. Here is my data:
Claim Paid Date-101 Claim Paid Date Claim Adjustment Date-10 Claim Adjustment Date-11 Claim Adjustment Date
10/23/2012 10/23/12 12:00 AM 9/4/2012 1 9/4/2012 1 9/4/12 12:00 AM
10/23/2012 10/23/12 12:00 AM 9/4/2012 1 9/4/2012 1 9/4/12 12:00 AM
10/23/2012 10/23/12 12:00 AM 9/4/2012 1 9/4/2012 1 9/4/12 12:00 AM
09/06/2011 09/06/11 12:00 AM 9/4/2012 1 9/4/2012 1 9/4/12 12:00 AM
10/23/2012 10/23/12 12:00 AM 8/21/2012 8/21/2012 8/21/12 12:00 AM
09/06/2011 09/06/11 12:00 AM 8/21/2012 8/21/2012 8/21/12 12:00 AM
The strange thing is that all of the dates in the "Claim Paid Date" column have a zero for padding if the month or day is < 10. This makes the convert come out just fine but where the month or day is < 10 and doens't have a zero is where I get my problem.
You have a string source, not a DATETIME source.
What happens with DATETIME:
SELECT GETDATE() -- DATETIME
,CAST(GETDATE() AS DATE) --DATE
,CONVERT(VARCHAR(10),GETDATE(),101) --101 format
Result:
DateTime Date 101 Format
----------------------- ---------- ----------
2013-09-24 13:58:48.880 2013-09-24 09/24/2013
What happens with strings parading as DATETIME:
DECLARE #fake_date VARCHAR(25) = '10/23/12 12:00 AM'
SELECT CAST(#fake_date AS DATETIME) --DATETIME
,CAST(#fake_date AS DATE) --DATE
,CONVERT(VARCHAR(10),#fake_date,101) --101 format
Result:
DateTime Date 101 Format
----------------------- ---------- ----------
2012-10-23 00:00:00.000 2012-10-23 10/23/12 1
So perhaps you want:
CONVERT(VARCHAR(10),CAST(#fake_date AS DATE),101)
The correct way to do this is to store the data as DATETIME in the first place. Currently you are storing the data as strings, and you shouldn't be doing this, for a variety of reasons:
you lose the ability to sort (9/1/2012 will sort after 12/12/2012) without converting first. Converting is expensive.
you lose the ability to perform meaningful range queries without converting first (again, 9/1/2012 > 12/12/2012)
you lose all means of built-in validation - anyone can enter 13/33/2999 or 02/32/2099 or simply foo as a "date"
you lose the ability to perform date-related functions such as DATEADD, DATEPART or DATEDIFF against these columns without first converting
you need to convert to another type first before you can perform a conversion that will allow you to do things like trim time or present the date in a specific format
If you can't fix the table design and want to continue storing dates using the wrong data type, then the next best thing is to simply format the string in the client. If the client knows it's a date/time, then using .Format() or .ToString() should allow you to present the date without the time in whatever format you want.
You should be presenting dates to users in unambiguous formats, since you never know when some of your readers will see 6/12/2012 and not be sure if that's June 12 or December 6 (Canadians and Americans will see those differently, for example). So you can use, as an example:
DateVariable.Format('yyyy-MM-dd')
This will present an unambiguous date like 2012-06-12, which can only be misinterpreted in some very isolated regions and age groups in France (where y-d-m seems to remain in vogue).
However, if you absolutely want to present the ambiguous format, you can just use:
DateVariable.Format('MM/dd/yyyy')
...with no reason to change your SQL query at all. If, for some reason, you absolutely want or need to do this at the query level, then you can use:
SELECT CONVERT(CHAR(10), CONVERT(DATE, col), 101) -- mm/dd/yyyy
If you want to use less ambiguous forms, like yyyymmdd or yyyy-mm-dd, you can use:
SELECT CONVERT(CHAR(8), CONVERT(DATE, col), 112) -- yyyymmdd
SELECT CONVERT(CHAR(10), CONVERT(DATE, col), 120) -- yyyy-mm-dd
But again, conversion at the database layer is expensive, whereas string formatting at the client layer (where you're already handling these things as strings at that final step) is relatively cheap. You should be keeping these as date values as long as possible, both on the way in and on the way out of the database. There is just no advantage to treating them as strings anywhere SQL Server is concerned.
So, summary:
fix the table
perform the conversion on the client (preferably to an unambiguous format)
if you can't perform the conversion on the client, use a double-nested CONVERT (again, preferably to an unambiguous format)

Comparing Time in SQL Server 2008

Here is my table. I need a query which returns the shift id for a specified time
How can I get the value?
shift_ID shift_From shift_To
1 2010-09-21 10:00:00.000 2010-09-21 18:10:00.000
2 2010-09-21 20:00:00.000 2010-09-21 05:00:00.000
Suppose I am giving 02:00:00 as input I need to get the shift ID as 1. How can I do this?
Try:
SELECT shift_ID
FROM time_shift
WHERE
DATEDIFF(hour, shift_From, shift_To) = 2 -- your input
See more about DATEDIFF on MSDN
The first argument is the time part you're specifying to DATETIFF (hour, minute, second).
If your input is strictly like 02:00:00 you need to parse it to determine what specify as the first argument.
To determine does the specified date belong between 2 others, use:
SELECT shift_ID
FROM time_shift
WHERE
CAST(shift_From AS TIME) < CAST(#input AS TIME)
AND
CAST(#input AS TIME) < CAST(shift_To AS TIME)
-- you can specify operators inclusiveness, i.e. <= >= etc
-- or
CAST(#input AS TIME) BETWEEN (CAST(shift_From AS TIME), CAST(shift_To AS TIME))
See more about TIME on MSDN