Dynamic order by date data type in Oracle using CASE - oracle

My code in the stored procedure:
SELECT * FROM
my_table ir
WHERE
--where clause goes here
ORDER BY
CASE WHEN p_order_by_field='Id' AND p_sort_order='ASC' THEN IR.ID end,
CASE WHEN p_order_by_field='Id' AND p_sort_order='DESC' THEN IR.ID end DESC,
CASE WHEN p_order_by_field='Date' AND p_sort_order='ASC' THEN TO_CHAR(IR.IDATE, 'MM/dd/yyyy') end,
CASE WHEN p_order_by_field='Date' AND p_sort_order='DESC' THEN TO_CHAR(IR.IDATE, 'MM/dd/yyyy') end DESC;
Problem is that sorting is done based on the char, which comes out wrong for the date case. CASE statement, however, won't allow any other datatype other than char. So what is the solution in this case? I need to be able to pass the p_order_by_field into the stored procedure.
Thanks

Should be simple - just use ISO date format in your case:
TO_CHAR(IR.IDATE, 'yyyy-mm-dd')
and you should be fine.

Another problem could occure when you want to sort on the date difference (let say number of days between two days).
For example such a sort would return number 13 (days) before 9 (days).
The solution is that you concatenate length of date difference and the difference itself:
length(trunc(date2) - trunc(date1)) || to_char(date2 - date1)

Related

Re-write to_char function

When I use to_char function, It's know as internal_function in EP, and Index can't work in this column. Are there any way to re-write it? I don't want to create a function based index
This is my predicates code.
TO_CHAR(createdate,'dd-mm-yyyy') = TO_CHAR(systimestamp,'dd-mm-yyyy')
Many thanks.
Yes, this is exactly the reason we must use purely the date column on one side and a trunc(sysdate) like expression on the other instead of TO_CHAR while doing date comparisions.
where createdate >= trunc(sysdate)
and createdate < trunc(sysdate) + 1

How to retrieve currency amount as words using oracle sql

In the below code, I am trying to get the amount in words for the value in the AMOUNT column but can't seem to get it right. Anyone with an idea? Below the CREATE VIEW statement:
SELECT GLR3 AS RECEIPT_DOC_NO,
GLANI AS ACCOUNT_NUMBER,
GLSBL AS JDE_NO,
(SELECT YAALPH FROM PRODDTA.F060116 WHERE YAAN8 = T1.GLSBL) AS STAFF_NAME,
CASE GLDGJ WHEN 0 THEN TO_DATE (TO_CHAR (1 + 1900000), 'YYYYDDD')
ELSE TO_DATE (TO_CHAR (GLDGJ + 1900000), 'YYYYDDD') END AS GL_DATE,
GLEXA AS NARRATIVE,
GLLT AS LEDGER_TYPE,
GLSBLT AS SUBLEDGER_TYPE,
GLCRCD AS CURRENCY_CODE,
CASE GLAA WHEN 100 THEN ROUND (GLAA / 100, 2) ELSE ROUND (GLAA / 100, 2)
END AS AMOUNT,
(SELECT TO_CHAR(TO_DATE(T1.GLAA,'J'),'JSP')) FROM DUAL) AS AMOUNT_INWORDS
FROM PRODDTA.F0911 T1;
My code is failing with
ORA-00923: FROM keyword not found where expected.
ORA-00923: FROM keyword not found where expected.
Indicates a syntax error. In this case you have three ( and four ):
(SELECT TO_CHAR(TO_DATE(T1.GLAA,'J'),'JSP')) FROM DUAL) AS AMOUNT_INWORDS
The compiler is not expecting the second ) after 'JSP'.
The scalar cursor is unnecessary, so the simplified and corrected version would be:
TO_CHAR(TO_DATE(T1.GLAA,'J'),'JSP') AS AMOUNT_INWORDS
ORA-01854: julian date must be between 1 and 5373484
5373484 is the Julian date for 31-DEC-9999 which is the maximum date allowed in Oracle. This poses an absolute limit on the number which we can spell using JSP mask ... in one go. However, we can use PL/SQL to break larger numbers into chunks and spell those instead. The inestimable Tom Kyte wrote such a function and published it on the AskTom site. Find it here.
I think the value i'm trying to write in words has decimal values (400.00) hence the ORA-01854 error.
The Tom Kyte I linked to does address that issue further down the page. It's this comment here.
Data retrieved in amount column is preceded by a negative symbol when it shouldn't be,
If you simply want to ignore negative values then apply the ABS() function to give you the absolute value.

Oracle: filter query on datetime

I need to restrict a query with a
SELECT ... FROM ...
WHERE my_date=(RESULT FROM A SELECT)
... ;
in order to achieve that I am using as result of the select a timestamp (if I instead use a datetime I get nothing from my select probably because the format I am using trims the datetime at the second).
Sadly this is not working because these kindo of queries:
select DISTINCT TO_DATE(TO_TIMESTAMP(TO_DATE('25-10-2017 00:00', 'dd-MM-yyyy HH24:MI'))) from DUAL;
return an
ORA-01830: date format picture ends before converting entire input string
how to deal with timestamp to date conversion?
If you want to just compare and check only he dates use trunc on both LHS and RHS.
SELECT ... FROM ...
WHERE trunc(my_date)=(select trunc(RESULT) FROM A)
... ;
This will just compare the dates by truncating the timestamp values
You can use the combination of "TRUNC" and "IN" keywords in your query to achieve what you are expecting. Please check the below query sample as a reference.
SELECT * FROM customer WHERE TRUNC(last_update_dt) IN (select DISTINCT (TRUNC(last_update_dt)) from ... )
Cheers !!

Oracle SQL To compare 1 or 2 or more dates to be within a given period

I have a scenario where I need to compare 2 or more dates for given period.
I'm able to succeed when comparing 1 date to a period using between function. But challenge is when I have 2 dates to compare in parallel, getting single row sub query error
select A
from ORDER
where Date1 between sysdate and (sysdate-10)
Above query works fine for single date, please help to get a solution when I have Date 1 and Date 2 and need to compare against the same period (sysdate and (sysdate-10)) and I may have more than 2 dates as well.
Thanks
Shankar
Not having a proper description of your tables or the data they contain, it is difficult to know what you want.
Perhaps something like:
SELECT A
FROM ORDER
GROUP BY A
HAVING COUNT( CASE WHEN datecolumn BETWEEN SYSDATE - 10 AND SYSDATE THEN 1 ELSE NULL END ) > 0

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.

Resources