Subtracting Dates ORA01847 - oracle

I am a newbie to Oracle. I have been looking at the examples how to subtract between two days with to_Date.
However, every time I run this with to_date logic
SELECT (to_date((SELECT PAYMENT_DATE FROM INVOICES WHERE INVOICE_ID =3) - to_date((SELECT INVOICE_DUE_DATE FROM INVOICES WHERE INVOICE_ID= 3)))) FROM DUAL; I ended up getting this error: ORA-01847: day of month must be between 1 and last day of month
Payment Date is : 15-SEP-17 Invoice Due Date is: 24-JUN-17
Is there a simple way to calculate the difference in days between two columns?
Thanks in advance.

you don't need to convert with by using to_date without formatting like 'dd.mm.rrrr'. i.e. omit to_date clauses. Substracting dates yield a number ( assuming both column PAYMENT_DATE, INVOICE_DUE_DATE are in date type )
SELECT (SELECT PAYMENT_DATE FROM INVOICES WHERE INVOICE_ID =3) - (SELECT INVOICE_DUE_DATE FROM INVOICES WHERE INVOICE_ID= 3) INTO v_day FROM DUAL;
where v_day is a number. By the way, it's better to use in this way:
SELECT ( PAYMENT_DATE - INVOICE_DUE_DATE ) INTO v_day FROM INVOICES WHERE INVOICE_ID =3

Related

How to use complex condition in insert into select query in oracle

I want to insert some records with insert into select query in oracle. My condition should be when month of CREATE_DATE in SITA_HOSTS table is equal with month of sysdate - 1. Now my question is what should I write for the where statement?
This is my code:
DECLARE
p_year VARCHAR2(50);
n_year NUMBER;
n_month NUMBER;
j_year VARCHAR2(4);
j_month VARCHAR2(4);
c_month NUMBER;
BEGIN
SELECT TO_CHAR(sysdate, 'YYYY-MM-DD','nls_calendar=persian') INTO p_year FROM dual; --Change sysdate to jalali date
SELECT regexp_substr(p_year,'[^-]+', 1, 1) INTO j_year
FROM dual; -- Get year of jalalian sysdate
SELECT regexp_substr(p_year,'[^-]+', 1, 2) INTO j_month
FROM dual;--Get month of jalalian sysdate
n_year := TO_NUMBER(j_year);
n_month := TO_NUMBER(j_month);
insert into sita_orders(REL_MODULE,REL_ID,CREATE_DATE,AMOUNT,CUSTOMER_ID,PROJECT_ID,ORDER_STATUS,TITLE,YEAR)
SELECT 1,ID,sysdate,78787878,CUSTOMER_ID,PROJECT_ID,0,HOSTING_TITLE,j_year
FROM SITA_HOSTS
WHERE ????;
END;
At the end I should say that my date is Jalali date
Here is one way:
WHERE TRUNC(create_date,'MM') = ADD_MONTHS(TRUNC(SYSDATE,'MM'), -1)
TRUNC(date, 'MM') truncates to midnight on the first day of the month of the date.
It really depends on the content/meaning and data type of create_date within sita-hosts table. In addition to that is the requirement also unclear. Shall the insert also cover hosts that were created a couple of years ago or only the ones created last month.
solution for the hosts created during the last month. With trying to enforce the usage of indexes if there are some.
select <your select list>
from sita_hosts
where create_date between add_months(trunc(sysdate,'mm')-1) and trunc(sysdate,'mm')
and create_date < trunc(sysdate,'mm')
the second where clause will exclude all times that are on the start of this month just at midnight.
Thanks a lot guys. I have written this code and it works fine:
insert into sita_orders(REL_MODULE,REL_ID,CREATE_DATE,AMOUNT,CUSTOMER_ID,PROJECT_ID,ORDER_STATUS,TITLE,YEAR)
SELECT 1,ID,sysdate,100000,CUSTOMER_ID,PROJECT_ID,0,HOSTING_TITLE,TO_CHAR(sysdate, 'YYYY','nls_calendar=persian')
FROM SITA_HOSTS
WHERE
to_number(TO_CHAR(CREATE_DATE, 'MM','nls_calendar=persian')) <= to_number(TO_CHAR(sysdate, 'MM','nls_calendar=persian') - 1)
and ID not in (
select REL_ID from sita_orders where REL_MODULE=1 and YEAR=TO_CHAR(sysdate, 'YYYY','nls_calendar=persian')
);

Error: ORA-01848: day of year must be between 1 and 365 (366 for leap year) while extracting month and year from DateColumn(varchar(10))

SELECT TO_CHAR(TO_DATE(Column_d, 'dd/mm/yyyy'), 'YYYY-MM') as Date_y FROM Table_d
Even want to get quarter from the same date which is again giving me the error ORA-01848 like
SELECT (CASE WHEN (TO_CHAR(TO_DATE(Column_d, 'dd/mm/yyyy'), 'mm')) IN ('01','02','03') THEN 'Q1'
WHEN (TO_CHAR(TO_DATE(Column_d, 'dd/mm/yyyy'), 'mm')) IN ('04','05','06') THEN 'Q2'
WHEN (TO_CHAR(TO_DATE(Column_d, 'dd/mm/yyyy'), 'mm')) IN ('07','08','09') THEN 'Q3'
ELSE 'Q4' END as QTR
FROM Table_d
The way I see it, nothing of what you posted returns ORA-01848. It is - usually, if not always - related to the DDD date format mask which represents day number within the year.
For example, this is correct, as day number 001 equals the 1st of January:
SQL> select to_date('001-2020', 'ddd-yyyy') from dual;
TO_DATE('0
----------
01.01.2020
This returns ORA-01848 as there's no day 405 in this (nor any) year:
SQL> select to_date('405-2020', 'ddd-yyyy') from dual;
select to_date('405-2020', 'ddd-yyyy') from dual
*
ERROR at line 1:
ORA-01848: day of year must be between 1 and 365 (366 for leap year)
So: if you're doing anything like this, make sure that stored values are correct; I presume that not all of them are.
Besides, that's what happens when people store dates as strings into VARCHAR2 (instead of DATE datatype) columns. I'm not saying that you're the cause, but you certainly are a victim here.
[EDIT]
Julian date, eh? In a comment, you said that you used such a query:
Select TO_CHAR(TO_DATE(Julian_dateColumn+1900000, 'YYDDD'), 'YYDDD'), 'DD/MM/YYYY') as column_d from sometable
I doubt it as it is invalid (I suppose you have superfluous , 'YYDDD')).
Anyway, I have no idea why you tried to "convert" Julian date in such a manner. There's a simple and correct way to do so. Here's how:
This is today's date (21.05.2020) presented as Julian date:
SQL> select to_char(sysdate, 'j') julian from dual;
JULIAN
-------
2458991
That's kind of values you have stored in the table. In order to convert it to format you wanted (yyddd), you'd
SQL> select to_char(to_date(2458991, 'j'), 'yyddd') as column_d from dual;
COLUM
-----
20142
I suggest you use this instead of code you currently have, i.e.
SQL> create or replace view table_d as
2 select to_char(to_date(julian_datecolumn, 'j'), 'yyddd') as column_d
3 from sometable;
View created.
SQL> select * From table_d;
COLUM
-----
20142
SQL>

Oracle SQL display a different column depending on the date

I have a table that has 33 columns
Employee Month Day1 Day2 ...... etc. etc.
The day column represents the day of the month.
Is it possible to just display the Employee column and the Day of the month depending on today's date?
i.e.
12th May
Employee Day12
no idea where to start if it's possible. any help would be great
You get a record (here: month) with the WHERE clause. You get a certain column (here: day) with DECODE or CASE.
select
employee,
decode( extract(day from sysdate), 1, day1, 2, day2, 3, day3, ... ) as day
from mytable t
where t.month = extract(month from sysdate)
group by employee
order by employee;

Oracle Max Timetamp- subtract 45 minutes

I would like to build a query, which returns all records 45 Minutes before the max timestamp.
For example the record with the latest timestamp is:
01.09.2013 11:00:00
Now I would like to have all records from
01.09.2013 10:15:00 to 11:00:00
You can accomplish this by using Max aggregate/analytic function and interval statement:
Here is an example:
select col
from ( select col
, max(col) over() as max_time
from t1) t
where t.col between t.max_time - interval '45' minute
and t.max_time
Result:
Col
--------------------
01.09.13 11:00:00 AM
01.09.13 10:45:00 AM
01.09.13 10:30:00 AM
01.09.13 10:15:00 AM
SQLFiddle Demo
with cte as
(select max(the_timestamp_field) the_timestamp_field
from test)
select
*
from
test,cte
where
test.the_timestamp_field between cte.the_timestamp_field - (1/24*.75)
and cte.the_timestamp_field
will do it.
It can be simple and a little complicated, depending on how do you want to determine the creation time of the record. If there is a date column in your table which indicates the creation time it's simple:
SELECT columns
FROM table
WHERE date_column BETWEEN TO_DATE ('01.09.2013 10:15', 'MM.DD.YYYY HH24:MI') AND
TO_DATE('01.09.2013 11:00', 'MM.DD.YYYY HH24:MI')
If there is no date column you can use SCN_TO_TIMESTAMP(ORA_ROWSCN) pseudo column to determine the creation time, but please note that this feture requires 10g or greater version.

Oracle Analytics Date Range

While researching Oracle Analytics, I came across this query:
select an_id,
a_date,
min(a_date) over (
partition by an_id, trunc(a_date)
order by a_date
range between (2.5/24) preceding and (2.5/24) following
) mn,
max(a_date) over (
partition by an_id, trunc(a_date)
order by a_date
range between (2.5/24) preceding and (2.5/24) following
) mx
from a_table
I believe this finds the min and max dates for a given an_id and a_date within a 2.5 hour period.
My question is why does this comparison between a_date (a date) and 2.5/24 (a number) work and how can it be modified for ranges of days, months, or years?
The date type allows arithmetic where a unit of 1 is a day, so SYSDATE + 1 is tomorrow.
For example, try select to_char(sysdate + 1/24, 'DD-MON-YY HH:MM:SS') from dual -> 1 hour from now.
Here are the docs that talk about that specific analytic construct to give some foundational info and add to what jwilson mentioned.
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions001.htm#i97640
It's probably clearer to use intervals to specify window ranges:
http://download.oracle.com/docs/cd/B19306%5F01/server.102/b14200/functions104.htm#i89943
SELECT last_name,
hire_date,
salary,
SUM(salary) OVER (ORDER BY hire_date
RANGE NUMTOYMINTERVAL(1,'year') PRECEDING) AS t_sal
FROM employees;

Resources