Convert to datetime in SQL Server - sql

I have a simple SQL statement
select convert(datetime, '1/1/2018')
when I look at the output of it I see it is getting converted to 2018-01-01 00:00:00.000. Is it possible in the time section it gets the end of day time rather than the beginning of day?
I am using this to fetch data based on the converted date and it fails to retrieve this record 1/1/2018 15:10:43 because of the time thing.
Any suggestions?
Thanks
Update
Looks like I can do SELECT DATEADD(ms, -3, '5/31/2018') + 1 to solve my issue..Got the idea from Here

When I look at the output of it I see it is getting converted to
2018-01-31 00:00:00.000
I can't reproduce your result. select convert(datetime,'1/1/2018') doesn't return Jan 31st. It returns Jan 1st.
I am using this to fetch data based on the converted date and it fails
to retrieve this record 1/1/2018 15:10:43 because of the time thing
Since you are converting it to a DATETIME, it gets a time of 00:00:00 which is midnight. Thus, it fails to retrieve anything after midnight, like 15:10 on the same day. The easiest thing is to make your operator < the next day... so you don't have to account for hours, minutes, seconds, milliseconds...
where fetch < '20180102'
Notice I didn't use convert since SQL Server will handle that for us, but feel free to add it if it makes it clearer for you.
where fetch < convert(datetime,'20180102')
Also note that I used ANSI standars of YYYYMMDD. Other methods, which will cause issues when you use DATETIME2 or want a more precise measurement, is to add seconds to your date and use <=.
select dateadd(second,86399,convert(datetime,'20180101'))
Notice this has milliseconds of 000 though, so this can creep up on you later which is why I suggest using the next day.
For milliseconds...
select dateadd(millisecond,86399999,convert(datetime2,'20180101'))

If you are going to use a converted datetime to compare you need to be aware that it will always receive a time of 00:00:00.000. This will cause anything on that given date but with a greater time to be excluded from your results set.
To solve this issue you need to set the time on the field you are searching on to match. The code below will make every result in your datetime field have a time of 00:00:00.000, the same as your converted date.
(DATEADD(dd, DATEDIFF(dd, 0, my_col)

Related

Calculate time difference in SQL

We have two columns in SQL. one is total_work_time & next is total_exeption_time & both column data type is varchar
total_work_time value is 07:15:00
total_exeption_time value is 01:15:00
So I need to subtract total_work_time - total_exeption_time and the result will be 06:00:00.
I have tried with concat(DATEDIFF(HOUR,total_exeption_time,total_work_time),':', DATEDIFF(MINUTE,total_exeption_time,total_work_time))
But the result is 6:360. from this, 360 is the problem, it taken total minutes. I need the result structure like 06:00:00. How to fix this issue using SQL Server.
You should be storing time values in a TIME datatype - using the correct datatype is not only a best practice but will reduce the problems you face in future.
You can convert your VARCHAR values to TIME and then use the following calculation which takes the difference in seconds (your lowest unit of interest one assumes) and creates a new TIME result.
DECLARE #total_work_time TIME = '07:15:00', #total_exeption_time TIME = '01:15:00';
SELECT CONVERT(TIME, DATEADD(SECOND, DATEDIFF(SECOND, #total_exeption_time, #total_work_time), '00:00'));

Passing a user prompt as a date (or even a string) in Oracle SQL

I am using Business Objects, which runs on top of an Oracle SQL database. I do not have access to PL or any kind of SQL command line, and I do not have write access to the database. I can only run queries as single commands, requiring a defined set of columns to be output.
I am able to take data from user prompts, which appear in the SQL as:
#variable('Prompt1')
For example I can say:
SELECT
A.SomeDate
FROM
A
WHERE
A.SomeDate BETWEEN #variable('Start') AND #variable('End Date')
This is easy enough. It runs; requests the user to input some dates; and then returns all matches which are between them (inclusive).
The problem is, however, the users will be using Business Objects' "Infoview" system to run the queries, and the prompt system presents a date picker - which by default includes the time portion of the date ("01/01/2016 12:00:00 AM").
If the user does not delete the time portion, it can cause records to be missed, if the SomeDate value falls outside the selected time. For example, if I want to take all records of TODAY, then I technically want everything between 00:00:00 (midnight) and 23:59:59.
What I would really like to be able to do is use TRUNC around the query variable, as follows:
WHERE
A.SomeDate BETWEEN TRUNC(#variable('Start')) AND TRUNC(#variable('End Date'))
... however this causes a compilation error: "inconsistent datatypes: expected DATE got NUMBER". I don't know why Oracle would treat a prompt as a number datatype before it has compiled.
Does anyone know how I can take the #variable value and convert it into something that I will be able to truncate to a date value?
I'm therefore trying to figure out a way round this. One thing I had in mind was if I could possibly take the prompt variable and convert it explicitly into a date, using TO_DATE
Edit: it has been pointed out to me that TRUNC will have no effect, as the "12:00:00 AM" is already midnight. Therefore I think I have misunderstood TRUNC. It appears that it truncates it to midnight: whereas I thought it simply removed the time portion of the date altogether, meaning that matches would be returned at any time between 00:00:00 and 23:59:59.
What I really want is: if SomeDate has a time portion of, for example, 11:03 then how do I ensure that this will be included when an End Date prompt only specifies the day?
If you want to match SomeDate values between 00:00:00 on Start and 23:59:59 on End you can either adjust the end date to have that time instead of the default midnight, or use a range instead of between:
WHERE
A.SomeDate >= #variable('Start')
AND
A.SomeDate < #variable('End Date') + 1
The + 1 uses Oracle date arithmetic to give you the day after the variable value, so if the user picked "01/01/2016 12:00:00 AM" for both the start and end dates they would evaluate as 2016-01-01 00:00:00 and 2016-01-02 00:00:00 respectively. You can use the interval syntax if you prefer.
By using less-than for the upper limit you get all records where SomeDate is greater than or equal to the start date 2016-01-01 00:00:00 and less than the adjusted end date 2016-01-02 00:00:00 - which is the same as saying up to 2016-01-01 23:59:59. (Or if you has a timestamp column which has sub-second precision, up to 23:59:59.999...).
If the parser assumes the variable will be a string but it is actually a date - causing an 'inconsistent datatypes' error - then you could cast it to a date to satisfy the parser:
WHERE
A.SomeDate >= CAST(#variable('Start') AS DATE)
AND
A.SomeDate < CAST(#variable('End Date') AS DATE) + 1
or if it is actually passed as a string in the format you showed you can explicitly convert it:
WHERE
A.SomeDate >= TO_DATE(#variable('Start'), 'DD/MM/YYYY HH:MI:SS AM')
AND
A.SomeDate < TO_DATE(#variable('End Date'), 'DD/MM/YYYY HH:MI:SS AM') + 1
... making sure you have the correct format; from your example it could be DD/MM/YYYY or MM/DD/YYYY.
Try using TO_CHAR() and TO_DATE() together :
WHERE
A.SomeDate > TO_DATE(TO_CHAR(#variable('Prompt1'),'ddmmyyyy'),'ddmmyyyy')
First off, your problem is not coming from a time value in the prompt value, but rather the time value in SomeDate. Getting rid of that (making the date equal to midnight) will resolve the issue.
Your best bet, if you have the option of modifying the universe, is to create another object. I'm assuming you have an object named SomeDate whose SQL is a.somedate. Create another object, let's call it SomeDateOnly with a definition of trunc(a.somedate)* **.
Since SomeDateOnly will always be a midnight value, you can use Equal To with your prompts, which will produce SQL like:
trunc(a.somedate) = #variable('Prompt1')
which, when rendered by WebI, will produce:
trunc(a.somedate) = '16-08-2016 00:00:00'
This will return all records with a.somedate between 8/16/2016 at 00:00:00 and 8/16/2016 23:59:59.
Of course, you can use BETWEEN to select a range of dates:
trunc(a.somedate) between #variable('Start Date') and #variable('End Date')
Even if you don't have access to the universe, you can still use the above syntax by modifying WebI's generated SQL. (I'm assuming that's what you've been doing, anyway).
If the above works for you, then the following is irrelevant, but I wanted to address it anyway:
The reason for the "invalid number" error you were receiving is because of the way WebI formats dates for SQL. If you have this string in your query:
A.SomeDate = TRUNC(#variable('Prompt1'))
then WebI will replace the #variable(...) with a date string, and render it as the following before sending it to Oracle:
A.SomeDate = TRUNC('16-08-2016 00:00:00')
This, of course, makes no sense to the TRUNC() function as there's nothing to tell it that it's actually a date value.
You could to_date the prompt first, but you have to use the correct date format. WebI sets the nls_date_format for each session to a non-default format, so you would have to use:
A.SomeDate = TRUNC(to_date(#variable('Prompt1')),'dd-mm-yyyy hh24:mi:ss')
But again, this is irrelevant since you need to trunc somedate, not the prompt response values.
*Better still, rename SomeDate to SomeDateTime, and name the new object SomeDate
**This is pretty common - having multiple objects for the same source field. Sometimes you want the date/time value (for listing specific transactions), but sometimes you just need the date (for counting transactions by date). So having both available is very useful.

What is being compared? GETDATE() - TSQL

Hello I am wondering what gets compared or what the representation of the
GETDATE() > 1
is in the following line of T-SQL code below.
WHERE DATEDIFF(dd, CDF_AS_OFDATE, GETDATE()) > 1 )
What would happen if I decided to use 100 instead of 1? (I tried it, simply returned a smaller result set).
It's comparing the difference in days between CDF_AS_OFDATE and the current date, to see if it's more than 1 day. If you change it to those that have more than 100 days difference, it would most likely be a much smaller result set.
(You can determine it's in days by noticing that it's using DATEDIFF() with the dd parameter, which indicates you want the difference in days.)
it check if there was more than 1 day difference between the two date (then vs now)
SQL Server DATEDIFF() Function
The DATEDIFF() function returns the time between two dates.
Syntax
DATEDIFF(datepart,startdate,enddate)
Where startdate and enddate are valid date expressions and datepart can be one of the following:
day dd, d
Example
Now we want to get the number of days between two dates.
We use the following SELECT statement:
SELECT DATEDIFF(day,'2008-06-05','2008-08-05') AS DiffDate
Result:
DiffDate
61
The answer is in the DATEDIFF part of the WHERE clause.
It actually evaluates only those rows where the value of CDF_AS_OFDATE at least 1 day different from the current system date.
Where to start...
In your first example...
where getdate() > 1
First getdate() returns the current date and time-of-day as a datetime value. If you read the documentation, you'll discover that (1) there is no implicit conversion from datetime to int, but there is an implicit conversion from int to datetime. That means the expression is pretty much identical to
where getdate() > convert(datetime,1)
The epoch (zero point) of the SQL Server calendar is 1900-01-01 00:00:00.000, which is what you get if you say convert(datetime,0) or convert(datetime,''). When you convert an int value to a datetime value, the integer value is taken to indicate an offset in days since the epoch. The conversion is performed by adding that many days to the epoch to get the resulting datetime value: convert(datetime,1) thus yields the datetime value 1900-01-02 00:00:00.000 and your expression is thus the equivalent of
where getdate() > '1900-01-02 00:00:00.000'
which expression will always be true unless you've seriously mucked with your systems clock.
In your second example...
where datediff( dd , CDF_AS_OF_DATE , getdate() ) > 1
getdate() as noted earlier gives you the current date and time-of-day.
datediff() returns the delta between two datetime values in the requested units of time. If you want to be pedantic about things (and I do), depending on the unit requested, the resulting value is not necessarily correct (depend on your definition of "correct"): what you get is the count of unit boundaries between the two datetime values. So even though exactly one second separates the two datetime values in the expression below,
datediff(dd,'Dec 31, 2013 23:59:59','Jan 1, 2014 00:00:00') returns 1 indicating a delta of 1 day, whilst
datediff(year,'Dec 31, 2013 23:59:59','Jan 1, 2014, 00:00:00') likewise returns1` indicating a delta of 1 year.
So your where clause is restricting the result set to rows where the delta (in days) from the as-of date to the current date/time is greater than 1.

Storing "Time" in database- What to use DateTime/Interger/VarChar

I want to save Date and Time of the user on various activities performed. For date I have decided to use DateTime Column in Database and for Time I am in dilemma what datatype to go for.
I know in sql server 2008 Time datatype has been introduced but I am using older version i.e. Sql Server 2005 so I need your suggest to prove my understanding true or false.
I have seen people using varchar or DateTime for storing time into database. But I am looking towards usage of Integer datatype.
Reason for my selection is performance.
Following is the justification that I am giving to myself.
Assumptions
Any data saved into database must agree following rules
Date will be stored in format mm/dd/yyyy hh:MM:ss where hh:MM:ss will always be 00:00:00
Time will be stored in valid format (from hh:MM:ss as hhMMss)
if hh is 00
then MMss
and if MM is 00
then ss
and if ss is 00
then 0
hh will range in between 0-23
MM will range in between 0-59
ss will range in between 0-59
i.e. few examples
00:00:00 = 0
00:01:00 = 100
01:00:00 = 10000
13:00:00 = 130000
Personal thought why it will perform better.
SELECT * FROM Log WHERE loginDate = '05/23/2011'
AND loginTime BETWEEN 0 AND 235959 --Integer Comparison
When using JOINS on the basis of DateTime considering join for Date part only.
JOIN two tables on the basis of Common Dates irrespective of Time.I think Type Conversion would heavily impact in such cases if using DateTime as the storage datatype.
Since Sql will have to do an integer comparison and no typecasting would be required hence it should perform better.
EDIT
One drawback I just identified is when I want to get the difference between two times that how much time has been spent between 3 days, hopefully then it would become a nightmare to manage throughout the application.
So why do you need 2 columns. If the DateTime column (loginDate) has an empty time 00:00:00 why not just use that empty space for loginTime and have one column.
WHERE loginDate >= '05/23/2011' AND loginDate < '05/24/2011'
If you're intent on using an integer, there's nothing wrong with it.
Bearing your edit in mind, your ideal solution is to put both date and time in the same column, a DATETIME:
You can then trivially figure the difference between start and end times with DATEDIFF
You can easily establish just the date portion with CONVERT(varchar(10), loginDate, 101)
You can easily establish just the time portion with CONVERT(varchar(10), loginDate, 108)
Storage issues might be resolved by using SMALLDATETIME, if precision < 1minute isn't required. SMALLDATETIME requires four bytes per column, which is the same as INTEGER, so you're making a significant net gain over using two columns.

SQL between vs >= startdate and <= enddate

I'm writing some SQL queries in PL/SQL that require me to filter the records based on date. The field is a date/time type, but since I don't really care about the time I figured I'll just omit it from my where clause.
So I'm writing something like
WHERE
f.logdate between to_date('2011/01/01', 'yyyy/mm/dd') and
to_date('2011/01/31', 'yyyy/mm/dd')
To get all the records for january. I read that this is supposed to be equivalent to
WHERE
f.logdate >= to_date('2011/01/01', 'yyyy/mm/dd') and
f.logdate <= to_date('2011/01/31', 'yyyy/mm/dd')
But my final results are not what I expected: there are less records when I use the BETWEEN keyword than when I explicitly state the bounds. Is it because my assumption of what BETWEEN does is wrong?
EDIT: ah nvm, it appears that the date is not the issue. There was a subquery that I was using that was filtering its result set by date as well and was specifying date/time while I'm not.
Could you show the type of the "logdate" field (the sql create sentence could help) ?
In some databases the date type is actually a datetime field, so if you are looking for dates after "Jan 01 2011", you are really looking for dates after "Jan 01 2011 12:00:00 p.m.".
It may be your case.
if the time is set to 0:00 or something strange like that it wont work properly.
The query retrieves the expected rows because the date values in the query and the datetime values stored in the RateChangeDate column have been specified without the time part of the date. When the time part is unspecified, it defaults to 12:00 A.M. Note that a row that contains a time part that is after 12:00 A.M. on 1998-0105 would not be returned by this query because it falls outside the range.
http://msdn.microsoft.com/en-us/library/ms187922.aspx