How to filter SQL by time (greater and less than)? - sql

I want to query a subset from a dataset. Each row has a time stamp of the following format:
2014-04-25T17:25:14
2014-04-25T18:40:16
2014-04-25T18:44:57
2014-04-25T19:10:32
2014-04-25T20:22:12
...
Currently, I use the following query to select a time-based subset:
time LIKE '%2014-04-25T18%' OR time LIKE '%2014-04-25T19%'
This becomes quite complicated when you start to filter by mintutes or seconds.
Is there a way to run a query that such as ...
time > '%2014-04-25T18%' AND time < '%2014-04-25T19%'
A regular expression would be okay, too.
The database is a SpatiaLite database. The time column is of type VARCHAR.

If the date is being treated as a string and based on the example above:
time LIKE '%2014-04-25T18%' AND time <> '%2014-04-25T18:00:00:000'
Otherwise, you could convert the date to seconds since midnight and add 60 minutes to that to create the range part of the filter
DECLARE #test DATETIME = '2014-04-25T17:25:14'
SELECT #test
, CONVERT(DATE,#test) AS JustDate
, DATEDIFF(s,CONVERT(DATETIME,(CONVERT(DATE,#test))), #test) AS SecondsSinceMidnight
-- 60 seconds * 60 minutes * 24 hours = 86400

Thanks to your posts and this answer I came up with this solution:
SELECT * FROM data
WHERE DATETIME(
substr(time,1,4)||'-'||
substr(time,6,2)||'-'||
substr(time,9,2)||' '||
substr(time,12,8)
)
BETWEEN DATETIME('2014-04-25 18:00:00') AND DATETIME('2014-04-25 19:00:00');

Related

Compare dates db2/400 vs SQL Server

I want to compare a date/time from SQL Server (type datetime-16) with db2/400 (type Z).
Typically I would like to know that that there are 60 seconds between 18:44 and 18:45
Each one has slightly different display characteristics.
SQL Server 2016-07-26 18:45:00.000
Db2/400 2016-07-26-18.45.00.000000
If I do this on my db2 database:
SELECT
MYDATETIME,
'2016-07-26 18:44:00.000',
MYDATETIME - '2016-07-26 18:44:00.000'
FROM #dates
I get this
MYDATETIME Constant value Numeric Expression
2016-07-26-18.45.00.000000 2016-07-26 18:44:00.000 100.000000
Db2 SQL seems quite generous to accept slightly different formats.
But query tells me that 1 minute difference = 100. Looks like I have a base 10 comparison happening here.
Using db2 timestamp function, I get the same result
SELECT
MYDATETIME,
'2016-07-26 18:44:00.000',
MYDATETIME - timestamp('2016-07-26-18.44.00.000000')
FROM #dates
How can I make comparisons that would give me difference in minutes (or hours or days)?
The results of subtracting two timestamps on DB2 for IBM i is known as a duration
You might find TIMESTAMPDIFF() useful
select
timestampdiff(2
, char(timestamp('2016-07-27 08:35:00.000000')
- timestamp('2016-07-27 08:34:00.000000')
)
)
from sysibm.sysdummy1
note that the first parameter is a small int with the following values
1 Microseconds
2 Seconds
4 Minutes
8 Hours
16 Days
32 Weeks
64 Months
128 Quarters
256 Years
The second parameter must be a character representation of a duration.
EDIT As pointed out by Clockwork-Muse, TIMESTAMPDIFF() is best used for short durations less than a month.
If you need accurate calculation for longer values, use the following form:
(DAYS(t1) - DAYS(t2)) * 86400 +
(MIDNIGHT_SECONDS(t1) - MIDNIGHT_SECONDS(t2))
Sample
select
(DAYS(timestamp('2016-07-27 08:35:00.000000'))
- DAYS(timestamp('2015-07-27 08:35:00.000000'))
) * 86400 +
(MIDNIGHT_SECONDS(timestamp('2016-07-27 08:35:00.000000'))
- MIDNIGHT_SECONDS(timestamp('2015-07-27 08:35:00.000000')))
from sysibm.sysdummy1
I know this is DB2/400, but in my experience the time operators work the same way, so from this article:
SELECT
MYDATETIME,
'2016-07-26 18:44:00.000',
MYDATETIME - timestamp('2016-07-26-18.44.00.000000') SECONDS
FROM #dates
Since I don't have a DB2 instance to test this on, the next thing I would try would be this:
SELECT
MYDATETIME,
'2016-07-26 18:44:00.000',
SECOND(MYDATETIME - timestamp('2016-07-26-18.44.00.000000'))
FROM #dates

Data in SQL not in proper date format, how to change it into the right format?

I have a column called ProcessTimeOnHold that shows how long it takes us to process an order.
Any order that takes less than 24 hours to process is shown in this format HH:MM:SS. As far as I can tell this data is in the proper date format however any order that takes longer than 24 hours shows up in this format D.HH:MM:SS So, if an order took 29 hours and 34 minutes it will show up as 1.05:34:00.
The problem I have is if I try to convert or manipulate the data for example into minutes the orders in the proper data format will work but anything after 24 hours will return an error.
For example if I try to convert to minutes with this:
LTRIM(DATEDIFF(MINUTE, 0, ProcessTimeOnHold))
It will convert all orders into minutes until it runs into an order with the D.HH:MM:SS format and then it will return this error:
Error Message: Conversion failed when converting datetime from
character string
Any way that I can change my entire column into datetime?
You might want to search for a less verbose solution, but this is one option, using string manipulation:
SELECT DATEDIFF(MINUTE, 0, (convert(time,RIGHT(ProcessTimeOnHold,8)))) +
(case when ProcessTimeOnHold like '%.%'
then
(cast((LEFT(ProcessTimeOnHold,CHARINDEX(ProcessTimeOnHold,'.')-1)) AS INT) * 24 * 60)
else 0 end) as TotalMinutes
(Edited based on comment)
Here's a way to get just the minutes:
declare #table table (ProcessTimeOnHold varchar(16));
insert #table (ProcessTimeOnHold)
values ('00:20:00')
, ('01:20:00')
, ('1.05:34:00');
select ProcessTimeOnHold
, datediff(minute,0,right(ProcessTimeOnHold,8))
+ isnull(nullif(replace(left(ProcessTimeOnHold,charindex('.',ProcessTimeOnHold)),'.',''),''),0) * 1440 'Minutes'
from #table
RETURNS:
ProcessTimeOnHold Minutes
----------------- -----------
00:20:00 20
01:20:00 80
1.05:34:00 1774
Try this one-
ANSI format: 2006.10.23
SELECT [ANSI]=CONVERT(char,CURRENT_TIMESTAMP,102)

SQL Command not properly ended ( oracle 11g for windows)

I m using this query to get a result of the difference between the start time and end time of an activity. Where the end time is null i wanted to put the minimum value as 500. Please advice and HELP!!
select * from table
where (end_time - start_time) * 24 * 60 > 1,
IF end_time IS NULL THEN '500';
So this is your query:
select * from table where (end_time - start_time) * 24 * 60 > 1;
But you want to treat a null end_time as 500. So use NVL or COALESCE to replace the null with 500:
select * from table where (nvl(end_time,500) - start_time) * 24 * 60 > 1;
IF end_time IS NULL THEN '500';
Just to make it more clear, '500' is not a number rather a string since it is enclosed within single quotation marks.
Now, end_time is. DATE data type or a timestamp, ideally. So, 500 makes no sense. You must convert it to appropriate type, whether 500 is days, hours, minutes, seconds, fraction of a second.
As in other answer it is suggested to use NVL(end_time, 500), it makes no sense. What does 500 - a date mean? Applying NVL is the need, however, you must convert it to the required value, else those are two different data types and Oracle won't allow it.
UPDATE
In my opinion,
Difference between two dates gives the number of days to the precision of seconds converted back to days. But, difference between an arbitrary number and a date makes no sense.
I assumed that start_time and end_time columns have number as datatype, for this calculation you need to select these specific columns and not all (*). Comparison is in where clause, this works in oracle11.
select ((NVL(END_TIME, 500)-START_TIME) * 24 * 60) from TABLE_NAME where ((NVL(END_TIME, 500)-START_TIME) * 24 * 60) > 1;

SQL. Select Unixtime for whole day

I am looking for a way to select a whole days worth of data from a where statement. Timestamp is in unix time such as (1406045122). I want to select the today's date of unix time range and find all the food that has been added in today. Thank in advance. This is the code I wrote. I'm not sure what I should put in the ( ????? ) part. I know it has to do with 60*60*24=86400 secs per day but I'm not too sure how I can implement this.
Select timestamp,food from table1 where timestamp = ( ????? );
Select timestamp,food
FROM table1
WHERE timestamp > :ts
AND timestamp <= (:ts + 86400);
replace :ts with the starting timstamp and you'll filter a whole day's worth of data
edit
This select query would give you the current timestamp (there may be more efficient ones, i don't work with sqlite often)
select strftime("%s", current_timestamp);
You can find more info about them here: http://www.tutorialspoint.com/sqlite/sqlite_date_time.htm
Using the strftime() function, combined with the date() function we can write this following query which will not need any manual editing. It will return the records filtered on timestamp > start of today & timestamp <= end of today.
Select timestamp,food
FROM table1
WHERE timestamp > strftime("%s", date(current_timestamp))
AND timestamp <= (strftime("%s", date(current_timestamp)) + 86400);
Your mileage will likely depend on your version of SQL but for example on MySQL you can specify a search as being BETWEEN two dates, which is taken conventionally to mean midnight on each. So
SELECT * FROM FOO WHERE T BETWEEN '2014-07-01' AND '2014-07-02';
selects anything with a timestamp anywhere on 1st July 2014. If you want to make it readable you could even use the ADDDATE function. So you could do something like
SET #mydate = DATE(T);
SELECT * FROM FOO WHERE T BETWEEN #mydate AND ADDDATE(#mydate, 1);
The first line should truncate your timestamp to be 00:00:00. The second line should SELECT only records from that date.

select statement using Between with datetime type does not retrieve all fields?

I'm facing a strange query result and I want to ask you why I'm facing this issue.
I store some datetime data into TestTable as following :
creation_time
-----------------------
2010-07-10 00:01:43.000
2010-07-11 00:01:43.000
2010-07-12 00:01:43.000
This table is created and filled as following :
create table TestTable(creation_time datetime);
Insert into TestTable values('2010-07-10 00:01:43.000');
Insert into TestTable values('2010-07-11 00:01:43.000');
Insert into TestTable values('2010-07-12 00:01:43.000');
when I execute this query , I get two rows only instead of three as I expected:
SELECT * FROM TestTable
WHERE creation_time BETWEEN CONVERT(VARCHAR(10),'2010-07-10',111) -- remove time part
and CONVERT(VARCHAR(10),'2010-07-12',111) -- remove time part
Or if I execute this query , the same issue ..
SELECT * FROM TestTable
WHERE CONVERT(datetime,creation_time,111) BETWEEN CONVERT(VARCHAR(10),'2010-07-10',111) -- remove time part
and CONVERT(VARCHAR(10),'2010-07-12',111) -- remove time part
My Question :
Why the last row ('2010-07-12 00:01:43.000') does not appear in
the result even if I set the date range to cover all the day from 2010-07-10 to 2010-07-12?
I use Sql server 2005 express edition with windows xp 32-bits.
I'm trying to don't use a workaround solution such as increasing the date range to cover additional day to get the days I want.
Thanks .
You need to remove the time part from creation_time as well. Just use the same CONVERT if it works.
Currently you're asking if 2010-07-12 00:01:43.000 is less than 2010-07-12 00:00:00.000, which is not true.
it does not show the date because you have removed the time part, which would make the date equivalent to '2010-07-12 00:00:00.000' and since the last row is greater than this, so it is not displaying in the query results.
Your script should look like this:
SELECT *
FROM TestTable
WHERE creation_time BETWEEN
convert(datetime, convert(char, '2010-07-10', 106))-- remove time part
and **DATEADD**(day, 1, convert(datetime, convert(char, '2010-07-**11**', 106))) -- remove time part and add 1 day
This script will return all between 2010-07-10 00:00:00 and 2010-07-12 00:00:00. Basically this means all items created in 2 days: 2010-07-10 and 2010-07-11.
Converting columns in your table for comparison can be costly and cause indexes to not be used. If you have a million rows in your table and you have an index on creation_time, you will be doing an index scan and converting all million values to a string for comparison.
I find it better to use >= the start date and < (end date + 1 day):
SELECT *
FROM TestTable
WHERE creation_time >= '2010-07-10'
AND creation_time < dateadd(day, 1, '2010-07-12')
And the reason your second one may not work is because format 111 uses slashes ("2010/07/10"), format 120 uses dashes ("2010-07-10"). Your converts aren't doing anything to your start and end date because you are converting a string to varchar, not a date. If you did this, it might work, but I would still recommend not doing the conversion:
SELECT * FROM TestTable
WHERE CONVERT(datetime, creation_time, 111) BETWEEN
CONVERT(VARCHAR(10), CONVERT(datetime, '2010-07-10'), 111) -- remove time part
and CONVERT(VARCHAR(10), CONVERT(datetime, '2010-07-12'), 111) -- remove time part
Date/time inclusive between 7/10/2010 and 7/12/2010:
SELECT * FROM TestTable
WHERE creation_time BETWEEN
CONVERT(VARCHAR,'2010-07-10',101) -- remove time part
and CONVERT(VARCHAR,'2010-07-13',101) -- remove time part