Invalid identifier using dow function - oracle

I'm getting invalid identifier when trying to display the dow() for first_day and last_day.
Can someone please help me out.
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
CREATE OR REPLACE FUNCTION dow(P_DAY DATE) RETURN VARCHAR2
IS
BEGIN
RETURN(TO_CHAR(P_DAY,'DAY'));
END;
/
with starting_date (datum) as
(select add_months(trunc(sysdate, 'yyyy'), 12) from dual)
select add_months(datum, level - 1) first_day,
dow(first_day),
last_day(add_months(datum, level - 1)) as last_day,
dow(last_day)
from starting_date
connect by level <= 12;

You can't use a column alias in the same level of query it is defined (except in an order-by clause). You would need to either use another subquery to get the first_day and last_day values and then call dow() for those in an outer query, or just repeat the calculations:
with starting_date (datum) as (
select add_months(trunc(sysdate, 'yyyy'), 12) from dual
)
select
add_months(datum, level - 1) as first_day,
dow(add_months(datum, level - 1)) as first_dow,
last_day(add_months(datum, level - 1)) as last_day,
dow(last_day(add_months(datum, level - 1))) as last_dow
from starting_date
connect by level <= 12;
FIRST_DAY
FIRST_DOW
LAST_DAY
LAST_DOW
2023-01-01
SUNDAY
2023-01-31
TUESDAY
2023-02-01
WEDNESDAY
2023-02-28
TUESDAY
2023-03-01
WEDNESDAY
2023-03-31
FRIDAY
2023-04-01
SATURDAY
2023-04-30
SUNDAY
2023-05-01
MONDAY
2023-05-31
WEDNESDAY
2023-06-01
THURSDAY
2023-06-30
FRIDAY
2023-07-01
SATURDAY
2023-07-31
MONDAY
2023-08-01
TUESDAY
2023-08-31
THURSDAY
2023-09-01
FRIDAY
2023-09-30
SATURDAY
2023-10-01
SUNDAY
2023-10-31
TUESDAY
2023-11-01
WEDNESDAY
2023-11-30
THURSDAY
2023-12-01
FRIDAY
2023-12-31
SUNDAY
fiddle
It's also not generally a good idea to use function names or other keywords as object names, including aliases; it's not complaining here, but I'd still consider calling the column something other than last_day.
You should also be aware the converting a date to a day name (among other formats) is affected by the session NLS settings, so someone else running this might see the names in a different language. And by default the day names are padded with spaces, which you might not be expecting.

Related

How to handle weekday calculation with date operation in Oracle

I need to handle specific scenario in StorProc where I need to do date calculation excluding Sat & Sun. Weekends are holiday I need to handle the data within working days.
I have implemented below code
if (purchase_date = (trunc(sysdate)-2) or purchase_date = (trunc(sysdate)-1)) Then
specific operation
As I have to exclude Sat & Sun by above implementation is giving wrong results obliviously . For example if today is Monday it has to give me back the date of Friday, my implementation is giving me Saturday or Sunday. I need to calculation with dates for weekdays only. Any help would be appreciated.
Thanks
To compare it to the previous week day, you can use:
IF purchase_date = TRUNC(SYSDATE)
- CASE TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW')
WHEN 0 THEN 3
WHEN 6 THEN 2
ELSE 1
END
THEN
-- Do something
NULL;
END IF;
TRUNC(date_value) - TRUNC(date_value, 'IW') will count the number of days since the start of the ISO week (which is always midnight on Monday).
Note: Do not use TO_CHAR(date_value, 'D') in an international setting as it will give a different result depending on which country you run it in (the week starts on Friday in Bangladesh, Saturday in some Middle-Eastern countries, Sunday in America and Monday in most of Europe).

Using current system month inside date functions

I am trying to write a query in Noetix that is pulling data from Oracle EBS. The query will have a column that checks to see if the date range of a field value of each record is within the current month then, if so, return another value. For example, the field value might be "23 JUN 2022", and I want to check to see if this date is within the "current" month.
So that I don't have to manually edit the report every time a month turns, I want the function to be 'rolling' where it checks the system time for the current month instead of me hard coding it in. I have the following expression, which works, but is static:
case
when
"TABLE1"."Scheduled_Date" >= TO_DATE('01 Jun 2022','DD Mon YYYY') AND
"TABLE1"."Scheduled_Date" < TO_DATE('01 Jul 2022','DD Mon YYYY') THEN
"TABLE1"."Selling_Price"
ELSE
TO_NUMBER('0')
END
How do I replace "Jun" and "Jul" in the expression above with a SYSDATE function that returns the current system month (for Jun), and the current system month +1 (for Jul)? I am experienced at MS Access SQL, but Oracle SQL is new to me. I can't figure out the proper syntax.
for the 1st day of the actual month you can use
add_months(last_day(trunc(sysdate))+1, -1)
for the 1st day of the next month you can use
last_day(trunc(sysdate))+1
There are various options you might choose; here's one of them (I'm setting date format so that you'd recognize values being returned; you don't have to do that):
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select trunc(sysdate, 'mm') first_of_this_month,
2 add_months(trunc(sysdate, 'mm'), 1) first_of_next_nonth
3 from dual;
FIRST_OF_THIS_MONTH FIRST_OF_NEXT_NONTH
------------------- -------------------
01.06.2022 00:00:00 01.07.2022 00:00:00
SQL>
Applied to your code:
case when "TABLE1"."Scheduled_Date" >= trunc(sysdate, 'mm')
AND "TABLE1"."Scheduled_Date" < add_months(trunc(sysdate, 'mm'), 1)
THEN
"TABLE1"."Selling_Price"
ELSE
TO_NUMBER('0')
END

Oracle sql how to get the date of a week

I have the following query that gets the week of a date:
SELECT pdm.serie, rta.matricula_ant, TO_CHAR (fecha, 'ww') semana,
SUM (rta.kms_acumulados) kms,
COUNT
(DISTINCT (CASE
WHEN v.secuencia BETWEEN rta.sec_origen AND rta.sec_destino
THEN v.cod_inc
ELSE '0'
END
)
)
- 1 numincidencias
FROM (SELECT ms.tren, ms.fecha_origen_tren, ms.secuencia, ri.cod_inc
FROM r_incidencias ri, mer_sitra ms
WHERE ri.cod_serv = ms.tren
AND ri.fecha_origen_tren = ms.fecha_origen_tren
AND ri.cod_tipoin IN (SELECT cod_tipo_iincidencia
FROM v_tipos_incidencias
WHERE grupo = '45')
AND ri.punto_desde = ms.cod_estacion) v,
r_trenes_asignar rta,
r_maquinas rm,
planificador.pl_dh_material pdm
WHERE rta.fecha BETWEEN TO_DATE ('21/09/2018', 'dd/mm/yyyy') AND TO_DATE ('21/09/2018',
'dd/mm/yyyy'
)
AND rta.serie >= 4000
AND rta.matricula_ant IS NOT NULL
AND rm.matricula_maq = rta.matricula_ant
AND rm.cod_serie = pdm.id_material
AND rta.grafico BETWEEN pdm.desde AND pdm.hasta
AND v.tren(+) = rta.tren
AND v.fecha_origen_tren(+) = rta.fecha
GROUP BY pdm.serie, rta.matricula_ant, TO_CHAR (fecha, 'ww')
ORDER BY pdm.serie, rta.matricula_ant, TO_CHAR (fecha, 'ww')
For example week 1
I want to display
week 1 : 1 january - 7 january
How can I get this?
Oracle offers the TRUNC(datestamp, format) function to manipulate dates this way. You may use a variety of format strings to get the first day of a quarter, year, or even the top of the hour.
Given a particular datestamp value, Oracle returns midnight on the first day of the present week with this expression:
TRUNC(datestamp,'DY')
You can add days to a datestamp. Therefore this expression gives you midnight on the last day of the week
TRUNC(datestamp,'DY') + 6
A WHERE-clause selector for all rows in the present week might be this.
WHERE datestamp >= TRUNC(SYSDATE,'DY')
AND datestamp < TRUNC(SYSDATE,'DY') + 7
Notice that the end of the range is just before (<) midnight on the first day of the next week. You need that because you may have datestamps after midnight on the last day of the week. (Beware using BETWEEN for datestamp ranges.)
And,
SELECT TO_CHAR(TRUNC(SYSDATE,'DY'),'YYYY-MM-DD'),
TO_CHAR(TRUNC(SYSDATE,'DY')+6,'YYYY-MM-DD')
FROM DUAL;
displays the first and last dates of the present week in ISO-like format.
Date arithmetic is cool. It's worth your trouble to study the date-arithmetic functions in your DBMS at least once a year.

SYSDATE between date in two fields for 6 month period Q

I am trying to set between a date range for 6 months in the past for two different fields that will group the data by month. How do I set such a between clause to achieve this?
SELECT TO_CHAR(mopend, 'MM-yyyy') AS month, MOPSTATUS, COUNT(*) MTS_COMPLETE_CNT
FROM MOPUSER.MOPACTIVITY
WHERE UPPER(MOPSTATUS) = 'COMPLETE'
AND TO_CHAR(MOPACTIVITY.MOPSTART, 'yyyy-mm-dd hh24:mi') BETWEEN TO_CHAR(sysdate,'YYYY-MM-DD')||' 06:02:00' AND TO_CHAR(sysdate,'YYYY-MM-DD')||' 22:59:59'
OR TO_CHAR(MOPACTIVITY.MOPEND, 'yyyy-mm-dd hh24:mi') BETWEEN TO_CHAR(SYSDATE,'YYYY-MM-DD')||' 06:02:00' AND TO_CHAR(SYSDATE,'YYYY-MM-DD')||' 22:59:59'
GROUP BY TO_CHAR(mopend, 'MM-yyyy'), MOPSTATUS
ORDER BY TO_CHAR(mopend, 'MM-yyyy'), MOPSTATUS
I will answer one part of your question first, and then based on your comments, I can give you the full query.
The following query returns the end points between which you want to search. T1 is 06:02 in the morning on the date that is six months back in time. T2 is the last second of today.
select sysdate
,add_months( trunc(sysdate) + interval '06:02' hour to minute, -6) as t1
, trunc(sysdate) + interval '23:59:59' hour to second as t2
from dual;
The above query returns the following (using yyyy-mm-dd hh24:mi:ss):
sydate: 2014-04-11 13:54:28
t1: 2013-10-11 06:02:00
t2: 2014-04-11 23:59:59
If I interpret you correctly, this is the time period you want to search?
For the second part of the answer, I'd need to know the following:
Can any of MOPSTART or MOPEND be null? If so, how do you want to treat those rows?
Do you want to include the end points, i.e. rows where MOPSTART >= t1? Or only where MOTSTART > t1?
Same as (2) but for MOPEND
What month do you want to group by (see below)?
For example, row (a), do you want count it once for each month, or only in JAN (started) or only in JUN(ended)?
JAN FEB MAR APR MAY JUN
a: |-------------------|
b: |---|---|
c: |---|
d: |-----------|
e: |--------|

Oracle BI: Select all records from last week

I need to get all records with a date between Sunday and Saturday last week, inclusive, for whatever date the query is run. For today, April 19th 2011, that would be from April 10th to April 16th.
When I entered the dates manually and converted the filter to SQL, I got the following syntax:
RESOLVED_DATE BETWEEN timestamp '2011-04-10 00:00:00' AND timestamp '2011-04-16 00:00:00'
I'm not even sure this is correct, because it seems to exclude dates on the 16th itself (shouldn't the time be 23:59:59?)
It is possible to determine the dates you want using combinations of next_day and regular date arithmetic. Below code should be pretty close, but it's untested and probably fails on some corner case, but at least you get the general idea :)
where resolved_date >= next_day( trunc(sysdate) - interval '14' day, 'SUN')
and resolved_date < next_day( trunc(sysdate) - interval '7' day, 'SUN')
trunc(sysdate) truncate the date to day; 2011-04-19 23:32:34 becomes 2011-04-19 00:00:00, i.e. removing the time component.
next_day(sysdate, 'SUN') returns the next sunday. If sysdate happens to be a sunday, the next sunday is returned.
Important: The day names have to be in the same language as your session.
The interval thing is just a standard way of adding/subtracting different units of time from a date.
Putting it all together, the logic for the 19th of April 2011 would be:
Truncate sysdate => 2011-04-19 00:00:00
subtract 14 days => 2011-04-05 00:00:00
Find the next sunday => 2011-04-10 00:00:00
...and
Truncate sysdate => 2011-04-19 00:00:00
subtract 7 days => 2011-04-12 00:00:00
Find the next sunday => 2011-04-17 00:00:00
..resulting in the following query:
where resolved_date >= timestamp '2011-04-10 00:00:00'
and resolved_date < timestamp '2011-04-17 00:00:00'
All resolved_dates that happened on or after the first second of the 10:th but before the first second of the 17:th would be included. Note that >= and < isn't equivalent to between.
A note on performance: I would make sure that Oracle correctly estimates the date range to be 7 days, and that the correct join order/method is used. If you expect the query to run for a while, you can afford to calculate the dates in the application and supply them as date litterals instead of computing them on the fly like I did above.
take a look at the to_date function: http://psoug.org/reference/builtin_functions.html

Resources