PL/SQL funtion with If - oracle

I have a production records system, where the user selects the date, time, area, line, shift, and model. Introduce the number of fabric pieces in one hour in the field pieces. After adding another record, the user enters again the number of pieces, but it must also appear in another field, Total pieces, the total of pieces, that is, the sum of the current one plus the previous record.
This is the table
Date-------Time---------Area-------Line----Shift-----Model----Pieces-------Total volume
8/8/20-------7--------------A-----------1---------1--------XC1--------2--------------------2
8/8/20-------8--------------A-----------1---------1--------XC1--------3--------------------5
8/8/20-------9--------------A-----------1---------1--------XC1--------2--------------------7
The function should not add anything at the beginning of the day, and the following records should be added as long as the date, line, area, shift and model are the same.
I had planned to use a PL/SQL function where if the time is 7 (the start) it show the same number that was entered in pieces, but if it is another time (8 for example), select the pieces data in the database of the record that has the same date, area, line, shift, and model but the time is the previous one (hour-1).
I don't know if this can be done, I would appreciate your help.

I wouldn't store total_volume into a table; calculate it using sum function in its analytic form. This is, after all, Oracle Apex (I presume interactive or classic report).
Here's an example (sample data from lines #1 - 14; query that actually does the job begins at line #15):
SQL> with test (datum, time, model, pieces) as -- Expected result:
2 (select date '2020-08-08', 7 , 'XC1', 2 from dual union all -- 2
3 select date '2020-08-08', 8 , 'XC1', 3 from dual union all -- 5
4 select date '2020-08-08', 9 , 'XC1', 2 from dual union all -- 7
5 --
6 select date '2020-08-09', 7 , 'XC1', 1 from dual union all -- 1
7 select date '2020-08-09', 8 , 'XC1', 3 from dual union all -- 4
8 select date '2020-08-09', 10, 'XC1', 2 from dual union all -- 6
9 select date '2020-08-09', 11, 'XC1', 1 from dual union all -- 7
10 select date '2020-08-09', 12, 'XC1', 6 from dual union all -- 13
11 --
12 select date '2020-08-09', 9 , 'XC2', 5 from dual union all -- 5
13 select date '2020-08-09', 10, 'XC2', 4 from dual -- 9
14 )
15 select datum, time, model, pieces,
16 sum(pieces) over (partition by datum, model order by time) total_volume
17 from test
18 order by datum, model, time;
DATUM TIME MOD PIECES TOTAL_VOLUME
---------- ---------- --- ---------- ------------
08/08/2020 7 XC1 2 2
08/08/2020 8 XC1 3 5
08/08/2020 9 XC1 2 7
09/08/2020 7 XC1 1 1
09/08/2020 8 XC1 3 4
09/08/2020 10 XC1 2 6
09/08/2020 11 XC1 1 7
09/08/2020 12 XC1 6 13
09/08/2020 9 XC2 5 5
09/08/2020 10 XC2 4 9
10 rows selected.
SQL>

Related

How to select the first 5 dates from each group and put them in a single column separated by comma in Oracle?

I have a table like this:
Division
Region
Date of Last Visit
1
2
11/20/2021
1
2
11/18/2021
1
7
10/18/2021
1
7
11/19/2021
2
2
11/17/2021
2
3
09/20/2021
2
3
10/20/2021
I want to write a query that groups by the division and region columns and gives me the last 5 dates for each group separated by commas in a single column. Something like this:
Division
Region
Date of Last Visit
Today
Days since last visit
1
2
11/20/2021, 11/18/2021
sysdate
sysdate - max(date of last visit)
1
7
10/18/2021, 11/19/2021
sysdate
sysdate - max(date of last visit)
2
2
11/17/2021
sysdate
sysdate - max(date of last visit)
2
3
9/20/2021, 10/20/2021
sysdate
sysdate - max(date of last visit)
The last two columns are custom calculated columns that I also need for the final output table. Any help would be greatly appreciated as I have tried a lot of things but I keep getting errors about it not being grouped properly, possibly because of the two extra columns at the end. But even without that, I am not sure how to fetch only the last 5 dates per group in oracle.
Thanks!
You want to filter the greatest-n-per-group using the ROW_NUMBER analytic function and then aggregate:
SELECT division,
region,
LISTAGG(TO_CHAR(date_of_last_visit, 'DD/MM/YYYY'), ',')
WITHIN GROUP (ORDER BY date_of_last_visit DESC)
AS date_of_last_visit,
SYSDATE AS today,
TRUNC(SYSDATE - MAX(date_of_last_visit)) AS days_since_last_visit
FROM (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY division, region
ORDER BY date_of_last_visit DESC) AS rn
FROM table_name t
)
WHERE rn <= 5
GROUP BY
division,
region
Which, for the sample data:
CREATE TABLE table_name (division, region, date_of_last_visit) as
select 1, 2, date '2021-11-20' from dual union all
select 1, 2, date '2021-11-18' from dual union all
select 1, 7, date '2021-10-18' from dual union all
select 1, 7, date '2021-11-19' from dual union all
select 2, 2, date '2021-11-17' from dual union all
select 2, 3, date '2021-09-20' from dual union all
select 2, 3, date '2021-10-20' from dual;
Outputs:
DIVISION
REGION
DATE_OF_LAST_VISIT
TODAY
DAYS_SINCE_LAST_VISIT
1
2
20/11/2021,18/11/2021
30-NOV-21
10
1
7
19/11/2021,18/10/2021
30-NOV-21
11
2
2
17/11/2021
30-NOV-21
13
2
3
20/10/2021,20/09/2021
30-NOV-21
41
db<>fiddle here
Here you go; read comments within code.
SQL> with test (division, region, datum) as
2 -- sample data
3 (select 1, 2, date '2021-11-20' from dual union all
4 select 1, 2, date '2021-11-18' from dual union all
5 select 1, 7, date '2021-10-18' from dual union all
6 select 1, 7, date '2021-11-19' from dual union all
7 select 2, 2, date '2021-11-17' from dual union all
8 select 2, 3, date '2021-09-20' from dual union all
9 select 2, 3, date '2021-10-20' from dual
10 ),
11 temp as
12 -- rank rows per division/region, sorted by date column in descending order
13 (select t.*,
14 rank() over (partition by division, region order by datum desc) rnk
15 from test t
16 )
17 -- select up to 5 last rows per division/region
18 select division, region,
19 listagg(datum, ', ') within group (order by datum) dates,
20 trunc(sysdate) today,
21 --
22 (select trunc(sysdate) - a.datum
23 from temp a
24 where a.division = t.division
25 and a.region = t.region
26 and a.rnk = 1) days_since
27 from temp t
28 where rnk <= 5
29 group by division, region
30 order by division, region;
DIVISION REGION DATES TODAY DAYS_SINCE
---------- ---------- ------------------------------ ---------- ----------
1 2 11/18/2021, 11/20/2021 11/30/2021 10
1 7 10/18/2021, 11/19/2021 11/30/2021 11
2 2 11/17/2021 11/30/2021 13
2 3 09/20/2021, 10/20/2021 11/30/2021 41
SQL>

Full Date Range

1st time posting here, so sorry if I messed something up.
I'm trying to figure out how many units pre day are being used across multiple products given a date range.
So if I had a table like this:
Product_id
Start_date
End_date
Units
1
07/07/2021
07/09/2021
2
2
07/08/2021
07/10/2021
4
3
07/12/2021
07/12/2021
7
The output should be something like:
Date
Units
07/07/2021
2
07/08/2021
6
07/09/2021
6
07/10/2021
4
07/11/2021
0
07/12/2021
7
Here's one option; read comments within code.
SQL> with
2 calendar as
3 -- all dates between the first START_DATE and the last END_DATE.
4 -- You need it for outer join with data you have.
5 (select mindat + level - 1 as datum
6 from (select min(start_date) mindat,
7 max(end_date) maxdat
8 from test
9 )
10 connect by level <= maxdat - mindat + 1
11 )
12 -- final query
13 select c.datum,
14 nvl(sum(t.units), 0) units
15 from calendar c left join test t on c.datum between t.start_date and t.end_date
16 group by c.datum
17 order by c.datum;
DATUM UNITS
---------- ----------
07/07/2021 2
07/08/2021 6
07/09/2021 6
07/10/2021 4
07/11/2021 0
07/12/2021 7
6 rows selected.
SQL>

Create a product base table by date

I want to create a query that returns number of active products by colander date. I don’t have calendar dim table in database.
Current table
Product_name|prod_id|start_date|end_date
P1|1234|02/01/2020|30/05/2020
P1|2345|02/01/2020|31/12/9999
P1|3456|03/01/2020|31/12/9999
Expected Result
Calander_date|product_name|active_base
01/01/2020|P1|0
02/01/2020|P1|2
03/01/2020|P1|3
01/06/2020|P1|2
Create your own calendar, then - either in the database, as a "real" table (row generator technique helps here), or as a CTE (as I did in the following example):
SQL> with
2 test (product_name, prod_id, start_date, end_date) as
3 -- you have that table; don't type that
4 (select 'P1', 1234, date '2020-01-02', date '2020-05-30' from dual union all
5 select 'P1', 2345, date '2020-01-02', date '9999-12-31' from dual union all
6 select 'P1', 3456, date '2020-01-03', date '9999-12-31' from dual
7 ),
8 calendar (datum) as
9 -- create your own calendar table
10 (select date '2020-01-01' + level - 1
11 from dual
12 connect by level <= 10000 --> number of days you want in calendar
13 )
14 -- final query - join!
15 select c.datum,
16 t.product_name,
17 count(*) active_base
18 from calendar c join test t on c.datum between t.start_date and t.end_date
19 group by c.datum, t.product_name
20 order by c.datum;
DATUM PR ACTIVE_BASE
---------- -- -----------
02/01/2020 P1 2
03/01/2020 P1 3
04/01/2020 P1 3
05/01/2020 P1 3
06/01/2020 P1 3
<snip>
28/05/2020 P1 3
29/05/2020 P1 3
30/05/2020 P1 3
31/05/2020 P1 2
01/06/2020 P1 2
02/06/2020 P1 2
<snip>

split a string in oracle into multiple columns based on a delimiter [duplicate]

This question already has answers here:
How to convert comma separated values to rows in oracle?
(6 answers)
Convert delimited string to rows in oracle [duplicate]
(3 answers)
Closed 2 years ago.
Need some help with splitting a varchar field into multiple rows in oracle.
example:
in the given data sample, the order number is unique. I want to split the service code into multiple rows and each service code is separated by |
data sample
Thanks!
Here's an example.
Sample data is in lines #1 - 5 (you already have that in your table, don't type that); query that does the job begins at line #6.
SQL> with test (order_no, datum, service_cd) as
2 (select 17, date '2016-11-30', '2106|2100|2105' from dual union all
3 select 23, date '2016-11-30', '2043|2020|2023|2047' from dual union all
4 select 67, date '2016-11-30', null from dual
5 )
6 select order_no,
7 datum,
8 regexp_substr(service_cd, '[^|]+', 1, column_value) val
9 from test cross join
10 table(cast(multiset(select level from dual
11 connect by level <= regexp_count(service_cd, '\|') + 1
12 ) as sys.odcinumberlist))
13 order by order_no, datum, column_value;
ORDER_NO DATUM VAL
---------- ---------- ----------
17 30/11/2016 2106
17 30/11/2016 2100
17 30/11/2016 2105
23 30/11/2016 2043
23 30/11/2016 2020
23 30/11/2016 2023
23 30/11/2016 2047
67 30/11/2016
8 rows selected.
SQL>

Oracle APEX - converting a field from collection to type DATE

I have a page that grabs data from apex collection and one of the fields is date but since it is coming from collection it comes up as text. What is the best way to convert it to date?
Generally speaking, text (string) is converted to DATE with TO_DATE function, by applying the correct format mask. For example:
SQL> with test (text_value) as
2 (select '23.04.2019' from dual union all
3 select '04-2019-23' from dual union all
4 select '04 April 2019' from dual
5 )
6 select to_date(text_value, 'dd.mm.yyyy') result from test
7 where text_value = '23.04.2019'
8 union all
9 select to_date(text_value, 'mm-yyyy-dd') from test
10 where text_Value = '04-2019-23'
11 union all
12 select to_date(text_value, 'dd month yyyy', 'nls_date_language=english')
13 from test
14 where text_value = '04 April 2019'
15 /
RESULT
----------
23/04/2019
23/04/2019
04/04/2019
SQL>

Resources