Oracle OR statement - oracle

I need to select records where the ACTUAL_END_DATE is null or has a date that is no older than 90 days at the point of running the query.
This is what I have tried using but it is returning too many records, it seems to be ignoring the OR clause
CU.ACCOUNT_TYPE = 'C' AND ((C.ACTUAL_END_DATE IS NULL) OR (C.ACTUAL_END_DATE <= (SYSDATE + 90)))
Any help would be greatly appreciated.
Keith

It would be easier if you gave an example of a record that should not have been returned, but was.
That being said:
"no older than 90 days at the point of running the query."
Would indicate you want items where SYSDATE - ACTUAL_END_DATE is /less than or equal/ to 90, not greater than or equal to 90.
As written, presuming no end dates are in the future, you are getting all records that have already ended (since any end date will be less than or equal to SYSDATE, and the 90 becomes superfluous).
If this is the case, what you want is:
CU.ACCOUNT_TYPE = 'C' AND ((C.ACTUAL_END_DATE IS NULL) OR (C.ACTUAL_END_DATE >= (SYSDATE - 90)))

Related

Understanding a specific WHERE clause in Oracle

I saw this as part of an Oracle SQL code
where employer.eab_yr || employer.eab_no >= 20173
and employer.eab_yr || employer.eab_no <= 20202
Can anyone explain to me what this part of the code is doing?
It appears it's fetching values from the employer table where eab_yr is between the 3rd month of 2017 and the second month of 2020. Is that correct?
|| is the string concatenation operator, >= is the greater than or equal operator and <= is the less than or equal operator.
So it matches all rows where the string concatenation of the columns eab_yr and eab_no of employer is numerically greater than or equal to 20173 and numerically less than or equal to 20202.
That's all there is. What that means semantically cannot be answered without knowing the semantics of the relation(s (there might be more than one, we cannot tell as there was no FROM clause given)) and the attributes. You didn't disclose those.
Assuming the code is concatenating year and month and trying to find a range then the code does not work as you would expect.
If you put the range from September 2017 to December 2017 then you will get the query:
where employer.eab_yr || employer.eab_no >= 20179
and employer.eab_yr || employer.eab_no <= 201712
Now, 20201 is greater than the number 20179 and is less than the number 201712 so you would find that January 2020 is returned (and so would many other unexpected months).
If you want to fix it then use a 2-digit month:
where employer.eab_yr || LPAD( employer.eab_no, 2, '0' ) BETWEEN 201709 AND 201712
or use date literals:
where TO_DATE( employer.eab_yr || '-' || employer.eab_no, 'YYYY-MM' )
BETWEEN DATE '2017-09-01' AND DATE '2017-12-01'
or, even better, fix your table so that you have a single DATE column rather than individual year and month columns.
db<>fiddle here

Oracle - trunc(DateTime) between trunc(Sysdate - 104) and trunc(Sysdate - 75)

I want to select few data from a Oracle table of June month(June 1st to June 30th of 2017) and the start date will be from tomorrow(Sep 13th). Hence I wrote a query in below format,
select * from table where column1='Data1' and Column2='Data2'
and trunc(DateTime) between trunc(sysdate-104) and trunc(sysdate-75)
I'm not able to check this query as I don't have tool for this. I just wrote it in notepad and want to share to my friend.
My Question - Will trunc(DateTime) between trunc(sysdate-104) and trunc(sysdate-75) condition will give data between June1st to June31 or Does any Syntax issue there?
There is no problem with the syntax itself even though your formulation is time sensitive, which means that tomorrow it won't return the same result.
Instead, go with something like this :
AND TRUNC(DateTime) BETWEEN to_date('2016-06-01','YYYY-MM-DD')
AND to_date('2016-06-30','YYYY-MM-DD')
Just cast the date format to month/year and compare against that.
select *
from table
where column1 = 'Data1'
and column2 = 'Data2'
and to_char(DateTime, 'MMYYYY') = '062017';
Hi I think the most accurate would be:
select * from table where column1='Data1' and Column2='Data2'
AND DateTime BETWEEN TRUNC(sysdate-104)
AND TRUNC(sysdate-75)
+ interval '23' hour
+ interval '59' minute
+ interval '59' second;

convert minutes to hh/mi/ss format in oracle query

I want to know the query which converts minutes to the format of hh/mi/ss in Oracle.I 've already seen lot of same questions from many forums but nothing helped me to get the exact result.
The query I used -Select to_char(to_date(mod(100,60),'mi'),'hh/mi/ss') from dual;
But I don't know how to get the hour value.Because mod function returns only the remainder I don't know how to take the quotient part and substitute into the hour field.
I suppose there are two ways of storing "minutes" in an Oracle database - you can either store them in a field whose datatype is INTERVAL DAY TO SECOND, or you can store them in a NUMBER. The simplest case to handle is the INTERVAL - in this case, the TO_CHAR function converts the value to a string of the form SDD HH:MM:SS.FFFFFF, where 'S' is sign ('+' or '-' as intervals can be positive or negative), DD = days, HH= hours, 'MM' = minutes, 'SS' = seconds, and 'FFFFFF' = fractions; thus, to get the HH:MI:SS all we need to do is use the SUBSTR function, as in
SUBSTR(TO_CHAR(I_VAL), 5, 8)
where I_VAL is an INTERVAL DAY TO SECOND value.
If the value to be converted is in a numeric field it gets a bit messy as we have to compute the individual field values, then subtract the previous fields as part of getting the next field. However, since the value stored is in minutes instead of seconds it's not particularly difficult:
create table TST (N_VAL NUMBER,
I_VAL INTERVAL DAY TO SECOND);
INSERT INTO TST(N_VAL, I_VAL) VALUES (666, INTERVAL '666' MINUTE);
SELECT N_VAL,
TRUNC(N_VAL/60) AS HOURS,
N_VAL-(TRUNC(N_VAL/60) * 60) AS MINUTES,
0 AS SECONDS,
TO_CHAR(I_VAL),
SUBSTR(TO_CHAR(I_VAL), 5, 8) AS HMS_FROM_INTERVAL
FROM TST;
SQLFiddle here
Best of luck.

compare 13digit (millisecond) unix timestamp with date in oracle

A database column (VARCHAR2 datatype) stores the date/time as 13 digit (milliseconds
) unixtimestamp format. Now when I want to compare the column with a oracle date (in question), The error thrown as 'invalid number'
I tried both ways,
converting the 13digit number to Date and compare with the date in question like below. The expressions seems valid as they are printed in select query, but if i include in the where part, it throws 'invalid number'
Here 'value' is 13th digit unixtimestamp column of VARCHAR2 datatype.
select
TO_DATE('1970-01-01', 'YYYY-MM-DD') + value/86400000,
TO_DATE('2014-04-21', 'YYYY-MM-DD')
from dummytable
-- where and TO_DATE('1970-01-01', 'YYYY-MM-DD') + value/86400000 > TO_DATE('2014-04-21', 'YYYY-MM-DD')
converting the date in question to 13digit unixtimestamp and comparing with the database column.The expressions seems valid as they are printed in select query, but if i include in the where part, it throws 'invalid number'
.
select
value,
(to_date('2013-04-21', 'YYYY-MM-DD') - to_date('1970-01-01', 'YYYY-MM-DD')) * (1000*24*60*60)
from dummytable
-- where value > ((to_date('2013-04-21', 'YYYY-MM-DD') - to_date('1970-01-01', 'YYYY-MM-DD')) * (1000*24*60*60))
any pointers? Thanks in advance.
[EDIT- 1 day later] I see the problem now. There are some data (other rows) for the 'value' column that are non-numeric. But I have another column say field, where always field='date' return value as 13 digit timestamp. Now I think when 'where' condition executes, although the field='date' is in the condition, it is still validating the other values for 'value' which are non-numeric. Is there a way to avoid this ?
Your code works just fine. The problem is in your data. Some of your values is not a number.
create table test
(value varchar2(13));
insert into test(value) values('2154534689000');
--insert into test(value) values('2 54534689000');
select TO_DATE('1970-01-01', 'YYYY-MM-DD') + value/86400000
from test
where TO_DATE('1970-01-01', 'YYYY-MM-DD') + value/86400000 > TO_DATE('2014-04-21', 'YYYY-MM-DD');
This code works fine. But if you uncommented the second insert, you would get exactly the same invalid number error as you get.
UPD. Allan gave you a nice hint, but i feel that it can be good to explain you a bit about views. The fact that you select from a view CAN make a difference. A view is not stored somewhere physically, when you select from it, it is just "added to your query". And then Oracle Query Optimizer starts working. Among other things, it can change the order in which your where predicates are evaluated.
For example, your the view query can have a line where value is not null and it would normally show only 'good' values. But if your query has a predicate where to_date(value,'ddmmyyyy') > sysdate, Oracle can decide to evaluate your predicate earlier, because Oracle predicts that it would "cut off" more rows, thus making the whole query faster and less momery consuming. Of course, execution will crash because of an attempt to convert a null string to date.
I believe, that Allan in his answer that he gave a link to, gave a great way to solve this problem: "wrapping" your query in a subquery that Oracle can't "unwrap":
select value
from
(select value
from my_view
where rownum > 0)
where to_date(value,'ddmmyyyy') > sysdate
Hope that helps.

ORA-01873: the leading precision of the interval is too small

When I try to query differences between 2 timestamps in Oracle, the result returns the interval normally.
select NVL2(ERROR_OUT_TS, ERROR_OUT_TS-ERROR_IN_TS, null) from table
or
select interval '8 00:00:10' day to second from dual
But when I try to select rows with greater than some interval, Oracle give me this error.
where ERROR_OUT_TS - ERROR_IN_TS <= '00 00:02:00'
or
where ERROR_OUT_TS - ERROR_IN_TS >= interval '0 00:00:10' day to second
It keeps saying that "the leading precision is too small".
I am trying to return the interval like 0 00:00:00:000
It is working fine for other customers. Only few customers are experiencing it.
How to choose the correct precision?
Try:
select interval '8 00:00:10' day(4) to second(4) from dual;
What it does is that 'day' and 'second' are default 2 digits, this expands them to accept 4. You probably just need 3 though.

Resources