how to get last businessday of last month in oralce - oracle

I have data like this my table
2020-01-01 H
2020-01-02 B
2020-01-03 B
2020-01-04 B
.
2020-01-29 B
2020-01-30 H
2020-01-31 H
2020-01-02 H
2020-02-02 H
2020-02-03 B
2020-02-04 B
2020-02-05 B
.
now my problem is in the current month i need to check third business day i.e in this case 2020-02-05 i need to get last business day of last month. i.e.2020-01-29

By adding 2 columns:
row_number() over(partition by trunc(date_value,'MM'), day_type order by date_value) as rn_month_asc,
row_number() over(partition by trunc(date_value,'MM'), day_type order by date_value desc) as rn_month_desc
in a month the 3rd business day will have rn_month_asc=3 and day_type ='B' and the latest business day will have rn_month_desc=1 and day_type ='B', and easy to query other situations if you need to.

in the current month I need to check third business day
From Oracle 12, you can use:
SELECT date_value
FROM table_name
WHERE TRUNC(SYSDATE, 'MM') <= date_value
AND date_value < ADD_MONTHS(TRUNC(SYSDATE, 'MM'), 1)
AND day_type = 'B'
ORDER BY date_value ASC
OFFSET 2 ROWS
FETCH NEXT ROW ONLY;
Which, for the sample data:
CREATE TABLE table_name (date_value, day_type) AS
SELECT DATE '2020-01-01', 'H' FROM DUAL UNION ALL
SELECT DATE '2020-01-02', 'B' FROM DUAL UNION ALL
SELECT DATE '2020-01-03', 'B' FROM DUAL UNION ALL
SELECT DATE '2020-01-04', 'B' FROM DUAL UNION ALL
SELECT DATE '2020-01-05', 'B' FROM DUAL UNION ALL
SELECT DATE '2020-01-28', 'B' FROM DUAL UNION ALL
SELECT DATE '2020-01-29', 'B' FROM DUAL UNION ALL
SELECT DATE '2020-01-30', 'H' FROM DUAL UNION ALL
SELECT DATE '2020-01-31', 'H' FROM DUAL UNION ALL
SELECT DATE '2020-01-02', 'H' FROM DUAL UNION ALL
SELECT DATE '2020-02-02', 'H' FROM DUAL UNION ALL
SELECT DATE '2020-02-03', 'B' FROM DUAL UNION ALL
SELECT DATE '2020-02-04', 'B' FROM DUAL UNION ALL
SELECT DATE '2020-02-05', 'B' FROM DUAL;
If the current month was 2020-01 then the output is:
DATE_VALUE
04-JAN-20
I need to get last business day of last month
SELECT date_value
FROM table_name
WHERE ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -1) <= date_value
AND date_value < TRUNC(SYSDATE, 'MM')
AND day_type = 'B'
ORDER BY date_value DESC
FETCH FIRST ROW ONLY;
If the current month is 2020-02 then the output is:
DATE_VALUE
29-JAN-20
fiddle

Related

Concatenated Select List value returns 'not a valid month' when applied TO_DATE

I have month and year values from select list, concatenated them in a string. If TO_DATE is applied on the string, that returns 'not a valid month' error.
Below is my code snippet,
V_DATE_FROM_STR_TEST := TRIM('01-'||TRIM(TO_CHAR(:P3_FROM_MONTH))||'-'||TRIM(TO_CHAR(:P3_YEAR)));
V_DATE_TO_STR_TEST := TRIM('01-'||TRIM(TO_CHAR(:P3_TO_MONTH))||'-'||TRIM(TO_CHAR(:P3_YEAR)));
Error 'not a valid month' occurs on this line,
TRUNC(TO_DATE(V_DATE_FROM_STR_TEST, 'DD-MON-YYYY'))
I have tried printing by HTP.PRN(V_DATE_FROM_STR_TEST) that shows date 01-JAN-2020.
Adding LOVs
Month LOV
select to_char(add_months(trunc(sysdate, 'yyyy'), level - 1), 'MONTH') d,
to_char(add_months(trunc(sysdate, 'yyyy'), level - 1), 'MON') r
from dual
connect by level <= 12
Year LOV
select YEAR d, YEAR r
from (select to_number(to_char(sysdate,'yyyy')) -8 YEAR
from dual
UNION
select to_number(to_char(sysdate,'yyyy')) -7 YEAR
from dual
UNION
select to_number(to_char(sysdate,'yyyy')) -6 YEAR
from dual
UNION
select to_number(to_char(sysdate,'yyyy')) -5 YEAR
from dual
UNION
select to_number(to_char(sysdate,'yyyy')) -4 YEAR
from dual
UNION
select to_number(to_char(sysdate,'yyyy')) -3 YEAR
from dual
UNION
select to_number(to_char(sysdate,'yyyy')) -2 YEAR
from dual
UNION
select to_number(to_char(sysdate,'yyyy')) -1 YEAR
from dual
UNION
select to_number(to_char(sysdate,'yyyy')) YEAR
from dual
) order by year desc
I am guessing there are some unwanted character is added in the date string from select list value, how can I remove that?
If you switch to digits, things might improve.
Month LoV: display words, but return numbers:
select to_char(add_months(trunc(sysdate, 'yyyy'), level - 1), 'MONTH') d,
level r
from dual
connect by level <= 12;
Then use this for the resulting string:
to_date(lpad(:P3_FROM_MONTH, 2, '0') || :P3_YEAR, 'mmyyyy')
Also, all those TRIMs look unnecessary, but OK - I understand - you tried to fix the problem.
While not directly referenced you can simplify your "Year LOV" query.
select yr d, yr r
from ( select extract(year from sysdate)-level +1 yr
from dual
connect by level <= 9
)
order by yr desc;

Oracle: Is it possible to filter out duplicates only when they appear in succession?

Thank you in advance for your help.
I have a table that holds itinerary information for drivers. There will be times when the itinerary seems to have the same stop (but is several days apart). I'd like to be able to query the table and filter out any record where the address is the same AND the dates are consecutive.
Is this possible?
Thanks again,
josh
with tst as(
select timestamp '2020-08-01 00:00:00' dt, '123 street' loc from dual
union all
select timestamp '2020-08-01 00:00:00', '89 street' from dual
union all
select timestamp '2020-08-02 00:00:00', '456 airport' from dual
union all
select timestamp '2020-08-04 00:00:00', '456 airport' from dual
union all
select timestamp '2020-08-05 00:00:00', '67 street' from dual
union all
select timestamp '2020-08-06 00:00:00', '89 street' from dual
union all
select timestamp '2020-08-07 00:00:00', '123 street' from dual
)
select dt, loc
from (
select dt, loc, nvl(lag(loc) over(order by dt), 'FIRST_ROW') prev_loc
from tst
) where loc <> prev_loc;
fiddle
Another approach would be to use Tabibitosan method which assign consecutive rows a group number and then count number of rows per group.(found in asktom website).
with test_data as(
select date'2020-08-01' dt, '123 street' loc from dual
union all
select date '2020-08-01', '89 street' from dual
union all
select date '2020-08-02', '456 airport' from dual
union all
select date '2020-08-04', '456 airport' from dual
union all
select date '2020-08-05', '67 street' from dual
union all
select date '2020-08-06', '89 street' from dual
union all
select date '2020-08-07', '123 street' from dual
)
select max(dt),loc
from
(
select t.*
,row_number() over (order by dt) -
row_number() over (partition by loc order by dt) grp
from test_data t
)
group by grp,loc
having count(*) > 1;
Another approach using match_recognize available from 12c onwards.patter used {1,} says repeated one or more times
more to learn match_recognize here
with test_data as(
select date'2020-08-01' dt, '123 street' loc from dual
union all
select date '2020-08-01', '89 street' from dual
union all
select date '2020-08-02', '456 airport' from dual
union all
select date '2020-08-04', '456 airport' from dual
union all
select date '2020-08-05', '67 street' from dual
union all
select date '2020-08-06', '89 street' from dual
union all
select date '2020-08-07', '123 street' from dual
)
select *
from test_data
match_recognize (
order by dt
all rows per match
pattern (equal{1,})
define
equal as loc = prev(loc)
);
Playground: Dbfiddle

oracle query to retrieve closest and second closest future date based on the current date

I want to retrieve the closest and second closest future date based on the current date.
example :
current-date=28-07-2017
dates to be retrieve
28-07-2017
29-07-2017
or followed top two dates which are closest to current date.
plzz help me out in writing this query in oracle
Try this:
select sysdate,sysdate + level "Dates" From DUAL connect by level <= 1 ;
You can do this by using the dense_rank analytic function, like so:
WITH sample_data AS (SELECT 1 ID, to_date('01/07/2017', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 2 ID, to_date('02/07/2017', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 3 ID, to_date('02/07/2017', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 4 ID, to_date('03/07/2017', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 5 ID, to_date('04/07/2017', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 6 ID, to_date('05/07/2017', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 7 ID, to_date('06/07/2017', 'dd/mm/yyyy') dt FROM dual)
SELECT ID, dt
FROM (SELECT ID,
dt,
dense_rank() OVER (ORDER BY dt) dr
FROM sample_data
WHERE dt >= to_date('01/07/2017', 'dd/mm/yyyy'))
WHERE dr <= 2;
ID DT
---------- -----------
1 01/07/2017
2 02/07/2017
3 02/07/2017

How to query for a specific day of the month in Oracle

Trying to automate a query that will pull data for the current month where the day of the month (in the date field) is >= the 15th. Is this possible? If so, what is the syntax to achieve this?
I want to be able to run this query each month without having to change anything. So in May, it would automatically pull any item where the date was >= 5/15/16. In June, it would pull items where the date was >= 6/15/16. And so on.....
Any help in this would be greatly appreciated. Thanks
This will allow you to use any indexes you have on your date_field column:
SELECT *
FROM table_name
WHERE date_field >= TRUNC( SYSDATE, 'MM' ) + INTERVAL '14' DAY
AND date_field < ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), 1 );
If your date/time fields are of type timestamp you can do
select x from <your_table>
where EXTRACT(DAY from <timestamp field>) >=15
and EXTRACT(MONTH from <timestamp field>) = EXTRACT(MONTH FROM CURRENT_TIMESTAMP)
and EXTRACT(YEAR from <timestamp field>) = EXTRACT(YEAR FROM CURRENT_TIMESTAMP);
I think what you're after is something like:
with sample_data as (select 1 id, to_date('01/06/2016', 'dd/mm/yyyy') dt from dual union all
select 2 id, to_date('10/06/2016', 'dd/mm/yyyy') dt from dual union all
select 3 id, to_date('14/06/2016', 'dd/mm/yyyy') dt from dual union all
select 4 id, to_date('15/06/2016', 'dd/mm/yyyy') dt from dual union all
select 5 id, to_date('16/06/2016', 'dd/mm/yyyy') dt from dual union all
select 6 id, to_date('30/06/2016', 'dd/mm/yyyy') dt from dual union all
select 7 id, to_date('01/07/2016', 'dd/mm/yyyy') dt from dual)
select *
from sample_data
where dt >= trunc(sysdate, 'mm') + 14
and dt < last_day(trunc(sysdate)) + 1;
ID DT
---------- ----------
4 15/06/2016
5 16/06/2016
6 30/06/2016
(If you wanted rows with any date greater than the 15th of the current month, then remove the last predicate in the where clause.)

How to display the days in 1 week in oracle?

I'm stuck, please help me how to display the cover days (e.g Monday, Tuesday, etc) per week. Please help me. Thank you!
Desired Sample Output:
Data,03/24/2014,Monday,20,Tuesday,30.....
Data,03/31/2014,Monday,12,Tuesday,20.....
Here's my script:
select 'Data'
||','||to_char(d.dtime_day, 'MM/dd/yyyy')
||','||nvl(g.total, 0)
from tablename d
left join (
select trunc(t.create_time, 'IW') as ddate
,count(t.create_time) as total
from tablename1 t
left join tablename2 q
on q.id = t.queue_id
where t.create_time between trunc(sysdate,'IW')-12*7 and sysdate -1
and q.name not like 'Data1%'
or q.name not like 'Data2%'
or q.name not like 'Data3%'
or q.name not like 'Data4%'
or q.name not like 'Data5%'
or q.name not like 'Data6%'
or q.name not like 'Data7%'
or q.name not like 'Data8%'
or q.name not like 'Data9%'
group by trunc(t.create_time, 'IW')
) g on d.dtime_day = g.ddate
where d.dtime_day between trunc(sysdate,'IW')-12*7 and trunc(sysdate) -1
and trunc(d.dtime_day, 'IW')= d.dtime_day
order by d.dtime_day;
Output of the script:
Data,03/24/2014,42
Data,03/31/2014,25
You can also select the day of the week using to_char e.g.
select to_char(sysdate, 'Day') from dual;
Used in Oracle Apex for a LOV in a Form
select basic_day display, basic_day return
from
(select trim(to_char(basic_date, 'DAY')) basic_day
from
( select 7 my_row, trunc(sysdate, 'DAY') basic_date
from dual
union
select 1, trunc(sysdate, 'DAY') + 1
from dual
union
select 2, trunc(sysdate, 'DAY') + 2
from dual
union
select 3, trunc(sysdate, 'DAY') + 3
from dual
union
select 4, trunc(sysdate, 'DAY') + 4
from dual
union
select 5, trunc(sysdate, 'DAY') + 5
from dual
union
select 6, trunc(sysdate, 'DAY') + 6
from dual)
order by my_row
)

Resources