I am trying to query the minimum datetime from a column that is stored as nvarchar(max). There a a few tricky things with this query (at least for me)
There is more than just the date being stored within each record.
The position of the datetime is relative - although it does always appear in the format **(DD-MM-YY at HH:MM PM
There are multiple datetimes stored in each record - so not only do I need to locate and capture where there is a datetime, I need to find the minimum datetime within the record
I can't just change the format that the data is stored in - there is over a decade of information that is stored this way.
The column is called 'hdresp' - here is sample data:
**(03-Apr-14 at 09:44 AM email sent) -- Billy Bob: Upgrade ordered. **(02-Apr-14 at 04:16 PM email sent) -- Sammy Richards: I can give you another cable to if you think that will help but it just might be time for an upgrade. If you want to go that route I have to ask that you submit another request for New Hardware. **(02-Apr-14 at 03:17 PM email sent) -- Paul Smith: Michael Stop by my desk when you have a second.
What I would like to end up with is a query that identifies 02-Apr-14 at 3:17 PM as the minimum time and converts it to YYYY-MM-DD HH:MM:SS - for example 2014-04-02 15:17:00
Perhaps you could try this approach:
select hdresp, min(ts) as timestamp
from (
select hdresp, cast(substring(hdresp,delta+3,10)+substring(hdresp,delta+15,9) as datetime2) as ts
from (
select
hdresp,
charindex('**(',hdresp,1) as delta
from problem
union
select
hdresp,
charindex('**(',hdresp,1+charindex('**(',hdresp,1)) as delta
from problem
union
select
hdresp,
charindex('**(',hdresp,1+charindex('**(',hdresp,1+charindex('**(',hdresp,1))) as delta
from problem
union
select
hdresp,
charindex('**(',hdresp,1+charindex('**(',hdresp,1+charindex('**(',hdresp,1+charindex('**(',hdresp,1)))) as delta
from problem
) as temp1
where delta > 0
) as temp2
group by hdresp
;
See example here: http://sqlfiddle.com/#!3/a1a99/1
If there are more than 4 possible timestamps in a hdresp, just add more UNION SELECT... sections.
Thank you everyone for your help!
I ended up using this to extract and convert the minimum time from a string:
SELECT CONVERT(datetime, REPLACE(LEFT(RIGHT(hdresp, PATINDEX('%(**%', REVERSE(hdresp)) - 1), 21), 'at ', ''))
from tblhdmain
where hdindex = 211458
Which gave me the result:
2014-04-02 15:17:00.000
Related
I have Date Column Order_Date In date Time format Isdat
14/05/2018 13:13:06 This is format) , I need To Extract Today's Order before 14:00 P:M 'O' Clock and in Second Column I want to extract order after 15:00 P:M i.e Time from 15:00 P:M till 23:00 P:M in SQL SERVER,
Date Is in 24:00 Hor Format.
In output Order_date Should be 'yyyy-MM-dd hh:mm:ss ' Format
Like the others have said, the first thing you need to do is fix your data; storing a date as a varchar is a bad design choice. Always use a data type that is representative of you data; stores dates as a date, numbers as an int/decimal, etc.
According to the [documentation] there is no style code for dd/MM/yyyy hh:mm:ss, however, a quick SQL as below told me that style code 103 does work:
DECLARE #date varchar(50) = '31/05/2017 19:12:56';
WITH N AS (
SELECT 1 AS i
UNION ALL
SELECT i + 1
FROM N
WHERE I + 1 <= 150)
SELECT I, TRY_CONVERT(datetime2(0),#Date,I) AS Conversion
FROM N
OPTION (MAXRECURSION 150);
So, firstly, let's fix that data of yours. So, let's add the new column in and drop your old one.
ALTER TABLE YourTable ADD OrderDate datetime2(0);
UPDATE YourTable
SET OrderDate = CONVERT(datetime2(0),YourDateColumn,103);
GO
ALTER TABLE YourTable DROP COLUMN YourDateColumn;
EXEC sp_rename 'dbo.YourTable.OrderDate','YourDateColumn','COLUMN';
Ok, now we've got rid of your awful datatype, and got your new column. Good.
Now, you want to specifically query time here; if you're doing that, ideally you want to separate the value of the time and date out. Using something like WHERE CONVERT(time, YourDateColumn) BETWEEN '14:00' AND '15:00' makes the query non-SARGHable. Thus let's use a couple of computed columns for that:
ALTER TABLE YourTable ADD OrderDate AS CONVERT(date, YourDateColumn);
ALTER TABLE YourTable ADD OrderTime AS CONVERT(time, YourDateColumn);
Now, to your question at hand: "I need To Extract Today's Order before 14:00 P:M 'O' Clock and in Second Column I want to extract order after 15:00 P:M i.e Time from 15:00 P:M till 23:00 P:M in SQL SERVER". honestly, this is non-sensical; putting different orders based on time in different columns? I have no idea what you mean here, I'm afraid, and I have no sample data or expected results to work with. Thus, instead, i'll show you how to return orders after 14:00 but before '15:00` on a specific date:
SELECT *
FROM YourTable YT
WHERE OrderDate = '20170515'
AND OrderTime >= '14:00'
AND OrderTime < '15:00';
If you need more detail than that, you have a lot of comments asking you for more detail; I suggest you have a look at those. :)
I'm using SQL Server 2012 and I need to write a query that will extract data greater than a particular date. The date field is called 'CreatedOn" and dates are recorded in this format "2014-08-18 17:02:57.903".
Currently, the date part of my query stands as follows:
WHERE CreatedOn > '2014-08-18'
Problem is extracted data includes those of '2014-08-18'. It's like the > (greater than) is acting like >= (greater than or equal)!
How should I write my query if I need all data, say greater than '2014-08-18'?
Try the following condition. The problem is that 2014-08-18 is really 2014-08-18 00:00:00 (includes the hour), so any date time in that day will be greater.
WHERE CreatedOn >= '2014-08-19'
'2014-08-18' actually means '2014-08-18 00:00:00'
So if you do not want 18th you should put either '2014-08-19' or specify the hours you want your date to be bigger of.
As the others have said it is actually translating to CreatedOn > 2014-08-18 00:00:00
Instead try converting your datetime field to a short ate and compare those.
The 126 in Convert maps to the yyyy-mm-ddThh:mi:ss.mmm format.
WHERE CONVERT(char(10), CreatedOn,126) > '2014-08-18'
It sounds like when you're saying you want records "greater than '2014-08-18' you actually mean "records that occurred past 2014-08-18 23:59:59.999999" - you have to take into account time when working with dates, unless the time is otherwise removed (which in your sample data it was not.
You could do something like the following:
declare #gtDate datetime
set #gtDate = dateadd(d, 1, convert(datetime,convert(varchar(10), '2014-08-18', 101)))
....
WHERE CreatedOn >= #gtDate
Here we're taking your '2014-08-18', convert it to a varchar containing only the date (to help in case '2014-08-18' is ever '2014-08-18 12:00:00 as an example)
Then we convert the varchar back to a date, and add a day to it. In the end the statement says
Give me records that occured on 2014-08-19 or greater
EDIT:
Here's a fiddle demonstrating
http://sqlfiddle.com/#!6/90465/1
Note that we have 4 rows of data potential
insert into sampleData (Created)
select '2014-08-17'
union all select '2014-08-18'
union all select '2014-08-18 12:00:00'
union all select '2014-08-19'
union all select '2014-08-19 15:00:00'
only the bottom 2 rows (2014-08-19 and 2014-08-19 15:00:00) would be returned
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.
I am reading in from a datasource that is giving me time in a varchar in the format d:h:m:s:f, The day portion is always 0, the column represents a time of day. I would like to add this column to a datetime I already have.
Entry_Date Entry_Time
3/3/2009 12:00:00 0:16:17:6:0
8/24/2011 12:00:00 0:8:39:18:0
9/4/2010 12:00:00 0:12:33:18:0
If I was using C# I would just do TimeSpan.ParseExact but I do not know how to handle this in a purely sql fashion.
I would cast to time but I am using Sql Server 2005 and that does not have the time type.
How would I add the time to the neighboring datetime?
As simple as this:
select Entry_Date + cast(Entry_Time as datetime) combinedCol
from YourTable
Here is a working fiddle: http://sqlfiddle.com/#!3/85c3c/1
Enjoy!
Original Asker's note:
SQL can not handle the fractional seconds however they can be trimed off so the query would be
select Entry_Date + cast(left(Entry_Time, len(Entry_Time) - 2) as datetime) combinedCol
from YourTable
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