How to fix between that isn't inclusive for date - sql

I want to search for data between given dates. I'm able to get results that are between but it's not including the day at the beginning and end of between statement.
I tried just switching the days that use the between on such as adding or subtracting a day, but there's gotta be another way.
SQL:
WHERE "Date" Between '09/02/2019' AND '09/06/2019'
AND (sf.TemplateName = 'Nassco Lacp')
AND (sf.ProjectName = 'Crossbore Safety Program')
AND (sf.WorkOrderNumber LIKE '%2715%I1%')
I should get all data between those days including the work done on the the second and sixth, but for some reason I'm not getting stuff done on the sixth. HELP!

Don't use between with dates! The time component can cause a problem. Instead:
where date >= '2019-09-02' and
date < '2019-09-07' and -- note this is one day later
. . .
Most databases understand the YYYY-MM-DD for date constants.

In my experience this happends when the Date field is a timestamp data type. What happends is that a specific date such as 09/02/2019 it's interpreted as 09/02/2019 00:00:00 so any value before is exclured.
Try (ORACLE DBMS):
WHERE Trunc("Date") Between '09/02/2019' AND '09/06/2019'
Try (SQL Server):
WHERE cast("Date" As Date) Between '09/02/2019' AND '09/06/2019'

Related

Cannot pull correct time range

After executing this query
AND TRUNC(ITD.TRAN_DATE)>= '02-APR-18'
AND TO_CHAR(ITD.TRAN_DATE,'HH24MI')>='0600'
AND TRUNC(ITD.TRAN_DATE)<= '03-APR-18'
AND TO_CHAR(TRUNC(ITD.TRAN_DATE+1),'HH24MI')<='0030'
Everything after 6AM for April 2nd will show, but also times after 12:30AM the next day shows. What am I doing wrong here?
When we truncate a date we remove the time element. Consequently, a mask of 'HH24:MI' will return '00:00' which means that this will always be true regardless of the actual time component of ITD.TRAN_DATE:
AND TO_CHAR(TRUNC(ITD.TRAN_DATE+1),'HH24MI')<='0030'
Probably what you should do is something more straightforward, such as
where itd.tran_date >= date '2018-04-02' + (6/24)
and itd.tran_date <= date '2018-04-03' + (1/48)
Here's a SQL Fiddle demo comparing your WHERE clause with my suggestion.
Not sure what you want. Maybe this:
and to_char(itd.tran_date, 'YYYYMMDD-HH24MISS')
between '20180402-0600'
and '20180403-0030'
If so however, and if the table have many rows and tran_date is an indexed column, this might be a lot faster:
and itd.tran_date
between to_date('20180402-0600','YYYYMMDD-HH24MI')
and to_date('20180403-0030','YYYYMMDD-HH24MI')
In your question you assume the date_format to be DD-MON-YY. This might be the case now, for the environment you have today, but might not be so always. So it's good practice to use to_char or to_date on DATE values or strings.

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.

Remove Time from date field in Teradata

Im trying to remove the time portion of a date field I am pulling in. I am using Teradata. I tried
select cast(inv_dt as date) as invoice
from tablex
to no avail it still is showing 09/01/2015 12:00:00 AM
I dont want to cast it as a char as I need to use the field in a calculation for dates. Thank you.
Your cast(inv_dt as date) does exactly what you want, you can use it in your calculation for dates...
If it's still showing a time portion it's due to your client (maybe it assumes Teradata's DATE is similar to Oracle's including time).
Finally figured it out
select
cast(cast(inv.INV_DT- EXTRACT(DAY FROM inv.INV_DT) + 1 as date format 'mm/dd/yyyy') as char (10)) as inv_dt
from invoice inv

finding records between two dates and without entries elsewhere

I am having a problem setting up my date boundaries for the query.
I want records between 10/1/2010 and 12/31/2010, but without a record (activity) in calendar year 2011 to date.
where INV.Date_Imported BETWEEN '10/1/2010' AND '12/31/2010'
AND INV.RecID NOT IN (
SELECT RecID
FROM [VW_Invoice_All]
WHERE Date_Imported > '1/1/2011'
)
The only glaring issues I see is your Date_Imported line. If you want 1/1/2011 to be included in the NOT IN query, you need to change the query to
WHERE Date_Imported >= '1/1/2011'
BETWEEN is already inclusive, which is what you appear to be going for.
You don't have any times on your dates, but if they are DATETIME columns then that could be important. I would probably use:
WHERE
INV.Date_Imported >= '10/1/2010' AND
INV.Date_Imported < '1/1/2011' AND
NOT EXISTS (
SELECT *
FROM [VW_Invoice_All] I2
WHERE
I2.RecID = INV.RecID AND
I2.Date_Imported >= '1/1/2011')
(The EXISTS might give you better performance than the IN query, but test both.)
As gtcompscientist says:
BETWEEN is already inclusive...
so you only need:
WHERE INV.Date_Imported BETWEEN '2010-10-01 00:00:00' AND '2010-12-31 23:59:59'
To avoid any doubts, using the YYYY-MM-DD HH:mm:ss format means you don't need to worry about regional settings (UK dates are DD-MM-YYYY whilst US is MM-DD-YYYY but YYYY-MM-DD format is interpreted the same in both regions).
The addition of time (HH:mm:ss) ensures that you include all of 2010-12-31 i.e. from 00:00:00 to 23:59:59.
From my experience, the safest date format is 'yyyymmdd'. In the bank where I work at the moment it's the only format that works on both the production server and the test server.

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