Calculate Months separated (oracle 11G) - oracle

Dear Respectful Experts,
We have a table having Column TOTAL_MONTHS e.g. if
As shown below table need to Update using Update Statement.
TOTAL_MONTHS = 15 then Update the Column named "Months<=12" = 12 and Update the Column named "Months>12" = 3
another example in below table is
TOTAL_MONTHS =8 then Update Column named "Months<=12" = 8 and Update Column named "Months>12" = 0
Title
Amount
Total_months
Months<=12
Months>12
10101288
28000
15
12
3
10101289
40000
13
12
1
10101290
2000000
10
10
0
10101291
50000
14
12
2
10101239
6000
11
11
0
10101240
50000
8
8
0
10121003
690
12
12
0
CREATE TABLE "TEST3"
( TITLE VARCHAR2(100 BYTE),
AMOUNT NUMBER,
Total_Months NUMBER,
Months<=12 NUMBER,
Months>12 NUMBER
)
REM INSERTING into TEST3
Insert into TEST3 (TITLE,AMOUNT,"Total_Months","Months<=12","Months>12") values ('10101288',28000,15,null,null);
Insert into TEST3 (TITLE,AMOUNT,"Total_Months","Months<=12","Months>12") values ('10101289',40000,13,null,null);
Insert into TEST3 (TITLE,AMOUNT,"Total_Months","Months<=12","Months>12") values ('10101290',2000000,10,null,null);
Insert into TEST3 (TITLE,AMOUNT,"Total_Months","Months<=12","Months>12") values ('10101291',50000,14,null,null);
Insert into TEST3 (TITLE,AMOUNT,"Total_Months","Months<=12","Months>12") values ('10101239',6000,11,null,null);
Insert into TEST3 (TITLE,AMOUNT,"Total_Months","Months<=12","Months>12") values ('10101240',50000,8,null,null);
Insert into TEST3 (TITLE,AMOUNT,"Total_Months","Months<=12","Months>12") values ('10121003',690,12,null,null);
Somebody can help us please.
Thanks,
Regards,
Out Put Result as below
Title
Amount
Total_months
Months<=12
Months>12
10101288
28000
15
12
3
10101289
40000
13
12
1
10101290
2000000
10
10
0
10101291
50000
14
12
2
10101239
6000
11
11
0
10101240
50000
8
8
0
10121003
690
12
12
0

Use LEAST and GREATEST:
update test3
set "Months<=12" = LEAST(total_months, 12),
"Months>12" = GREATEST(total_months - 12, 0);
The same can be done with CASE expressions of course.
Demo: https://dbfiddle.uk/wB89f9eN
I don't consider it a good idea to store these calculated values in common table columns, by the way. Don't store data redundantly in a database. What would it mean, if some day you find a row containing total_months = 15, "Months<=12" = 12, "Months>12" = 10? Which value would be correct, which not? If you want to see the results like if they were table columns for convenience, use generated columns or a view instead.

If you want to calculate the months as full-years and part-years or as up-to-one year and more-than-one-year then you can calculate those values and do not need to have separate columns in the database that run the risk of becoming out of sync.
If you did want to represent the values in the table then you can use virtual columns:
CREATE TABLE "TEST3"(
TITLE VARCHAR2(100 BYTE),
AMOUNT NUMBER,
Total_Months NUMBER,
Full_Year_Months NUMBER
GENERATED ALWAYS AS (Total_months - MOD(total_months, 12)),
Part_Year_Months NUMBER
GENERATED ALWAYS AS (MOD(total_months, 12)),
"Month>12" NUMBER
GENERATED ALWAYS AS (GREATEST(total_months-12,0)),
"Month<=12" NUMBER
GENERATED ALWAYS AS (LEAST(total_months,12))
);
Which, for the sample data:
Insert into TEST3 (TITLE,AMOUNT,Total_Months) values ('10101288', 28000,15);
Insert into TEST3 (TITLE,AMOUNT,Total_Months) values ('10101289', 40000,13);
Insert into TEST3 (TITLE,AMOUNT,Total_Months) values ('10101290',2000000,10);
Insert into TEST3 (TITLE,AMOUNT,Total_Months) values ('10101291', 50000,14);
Insert into TEST3 (TITLE,AMOUNT,Total_Months) values ('10101239', 6000,11);
Insert into TEST3 (TITLE,AMOUNT,Total_Months) values ('10101240', 50000, 8);
Insert into TEST3 (TITLE,AMOUNT,Total_Months) values ('10121003', 690,12);
Insert into TEST3 (TITLE,AMOUNT,Total_Months) values ('12345678',1234567,45);
Then the table contains:
TITLE
AMOUNT
TOTAL_MONTHS
FULL_YEAR_MONTHS
PART_YEAR_MONTHS
Month>12
Month<=12
10101288
28000
15
12
3
3
12
10101289
40000
13
12
1
1
12
10101290
2000000
10
0
10
0
10
10101291
50000
14
12
2
2
12
10101239
6000
11
0
11
0
11
10101240
50000
8
0
8
0
8
10121003
690
12
12
0
0
12
12345678
1234567
45
36
9
33
12
fiddle

Related

How would I add an artificial termination date to the termination date column based on two different dates for the same patient id

I need to figure out a query that will compare two EFFECTIVE dates for a given patient number with different HMOs and determine which is the later date of the two and then populate a TERMINATION date field for only the older of the two effective dates with the last day of the previous month of the newer effective date of the two. This needs to be done across multiple patient, HMO, effective date combinations in a table.
SELECT * FROM tablename
The output is this:
HMO PATIENT EFFECTIVE TERMINATION
16 221135 01-APR-18
18 221135 01-OCT-17
12 251181 01-SEP-16
16 251181 01-MAR-15
12 271126 01-MAR-15
16 271126 01-DEC-16
12 291141 01-DEC-16
16 291141 01-FEB-19
12 391134 09-MAY-13
16 391134 01-APR-18
What I am trying to do via a query or queries is this:
HMO PATIENT EFFECTIVE TERMINATION
16 221235 01-APR-18
18 221235 01-OCT-17 3/31/2018
12 251381 01-SEP-16
16 251381 01-MAR-15 8/31/2016
12 2711126 01-MAR-15 11/30/2016
16 2711126 01-DEC-16
12 292241 01-DEC-16 1/31/2019
16 292241 01-FEB-19
12 391534 09-MAY-13 31-MAR-19
16 391534 01-APR-18
I've tried using a case statement but it is unsurprisingly creating four rows per patient, hmo combo and populating two of the rows with dates and leaving two blank:
SELECT DISTINCT
S.HMO
,S.PATIENT
,S.EFFECTIVE
,CASE WHEN S.EFFECTIVE > E.EFFECTIVE THEN LAST_DAY(ADD_MONTHS(S.EFFECTIVE, -1))
WHEN S.EFFECTIVE < E.EFFECTIVE THEN LAST_DAY(ADD_MONTHS(E.EFFECTIVE, -1))
ELSE NULL END AS TERMINATION
FROM tablename S INNER JOIN tablename E ON S.PATIENT=E.PATIENT
WHERE S.PATIENT =221135
Any ideas or advice would be welcome.
With sample data you posted:
SQL> select * from tablename order by patient, effective;
HMO PATIENT EFFECTIVE TERMINATIO
---------- ---------- ---------- ----------
18 221135 10/01/2017
16 221135 04/01/2018
16 251181 03/01/2015
12 251181 09/01/2016
12 271126 03/01/2015
16 271126 12/01/2016
6 rows selected.
such a MERGE might do:
SQL> merge into tablename a
2 using (select patient, max(effective) max_effective,
3 min(effective) min_effective
4 from tablename
5 group by patient
6 ) x
7 on (a.patient = x.patient)
8 when matched then update set
9 a.termination = x.max_effective - 1
10 where a.effective = x.min_effective;
3 rows merged.
Result is then
SQL> select * from tablename order by patient, effective;
HMO PATIENT EFFECTIVE TERMINATIO
---------- ---------- ---------- ----------
18 221135 10/01/2017 03/31/2018
16 221135 04/01/2018
16 251181 03/01/2015 08/31/2016
12 251181 09/01/2016
12 271126 03/01/2015 11/30/2016
16 271126 12/01/2016
6 rows selected.
SQL>

Access other values ​in a trigger before save Oracle

Is it possible to access the previous values ​​that have not yet been stored in the database?
I have a table related to a particular module (MOD) which I will call table XA.
I can insert multiple records into XA simultaneously they are going to be inserted, I cannot change this fact.
For example, the following data is inserted in XA
ID | ParentId | Type | Name | Value
1 | 1 | 5 | Cost | 20000
2 | 1 | 9 | Risk | 10000
And I need in this case to insert / update a record in this same table. A calculated value
At the moment of executing the trigger, the value with the name of Cost for example is inserted first, and then the value of Risk.
When evaluating the Risk, I must have the ability to know what the Cost value is to make the calculation and insert the calculated record.
I tried to create a Package to which I would feed the data, but I still have the same problem.
create or replace PACKAGE GLOBAL
IS
PRAGMA SERIALLY_REUSABLE;
TYPE arr IS TABLE OF VARCHAR2 (32)
INDEX BY VARCHAR2 (50);
NUMB arr;
END GLOBAL;
//Using in trigger
GLOBAL.NUMB (:NEW.ID || '-' || :NEW.ParentId) := :NEW.Value;
BEGIN
IF :NEW.Type == 9 AND GLOBAL.NUMB (5 || '-' || :NEW.ParentId) IS NOT NULL
THEN
// calculate and insert record
ELSE IF :NEW.Type == 5 AND GLOBAL.NUMB (9 || '-' || :NEW.ParentId) IS NOT NULL
// calculate and insert record
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
// NOT HAVE TWO INSERT TO SAME REGISTER
END;
Values ​​5 and 9 are for reference.
Both records are not always inserted, one or more can be inserted, even the calculated value can be imputed but must be replaced by the calculation.
And I can't create a view since there is an internal process that depends on this particular table.
Do you really really must store calculated value into a table? That's usually not the best idea as you have to maintain it in any possible case (inserts, updates, deletes).
Therefore, another suggestion: a view. Here's an example; my "calculation" is simple, I'm just subtracting cost - risk as I don't know what you really do. If calculation is very complex and should be run every time on a very large data set, yes - performance might suffer.
Anyway, here you go; see if it helps.
Sample data:
SQL> select * From xa order by parentid, name;
ID PARENTID TYPE NAME VALUE
---------- ---------- ---------- ---- ----------
1 1 5 Cost 20000
2 1 9 Risk 10000
5 4 5 Cost 4000
7 4 9 Risk 800
A view:
SQL> create or replace view v_xa as
2 select id,
3 parentid,
4 type,
5 name,
6 value
7 from xa
8 union all
9 select 0 id,
10 parentid,
11 99 type,
12 'Calc' name,
13 sum(case when type = 5 then value
14 when type = 9 then -value
15 end) value
16 from xa
17 group by parentid;
View created.
What does it contain?
SQL> select * from v_xa
2 order by parentid, type;
ID PARENTID TYPE NAME VALUE
---------- ---------- ---------- ---- ----------
1 1 5 Cost 20000
2 1 9 Risk 10000
0 1 99 Calc 10000
5 4 5 Cost 4000
7 4 9 Risk 800
0 4 99 Calc 3200
6 rows selected.
SQL>

Validating decimals in a column - oracle sqldeveloper

Im trying to come up with a test that validates decimals in a particular column (with 220000 records). For example for column A there shouldn't be any values with more decimals than 2, 1 is also ok.
for example :
Column A (datatype varchar)
48528.64
135082.54
5249.1
I tried with round function but than I get an error saying invalid number.
Also I would like to be able to change the number of decimals I put in the test to use with different columns
For example
Its 1 big table with all columns having datatype VARCHAR2(2000 char)
examples for columns:
total amount (value should have no more than 2 decimals)
48528.64
135082.54
349.1123 (not OK)
Balance (value should have no more than 2 decimals)
45428.64
1895082.11
5249.1483 (not OK)
Loan (value should have no more than 6 decimals)
100.64
88999.11654
1000.178875554 (not OK)
For each column I want to set up a seperate test that checks if the value is within the number of decimals allowed. So preferable a select statement with a where clause where I can adjust the numbers of decimals so I end up with all records having 1 or 2 decimals, or all the records that have more than 2 decimals
Invalid number error is due to the fact that you have something that isn't a number in that column, so when you apply numeric function to it, Oracle complains. That's what you get when you store numbers as strings. Don't do that.
Anyway, here's one option which shows what you might try to do: as these are strings, calculate number of digits right of the decimal point.
SQL> select * From test;
A
--------------------
48528.64 -- OK
135082.54 -- OK
5249.1 -- OK
1.2345 -- not OK
-25.553 -- not OK
SQL> select *
2 from test
3 where length(regexp_substr(a, '\d+$')) > 2;
A
--------------------
1.2345
-25.553
SQL>
If there are several columns and you'd like to check each of them using a separate table which holds allowed number of decimals, then you could do something like this:
SQL> with
2 big (total, balance, loan) as
3 (select 48528.64 , 45428.64 , 100.64 from dual union all
4 select 135082.54 , 1895082.11 , 88999.11654 from dual union all
5 select 349.1123 , 5249.1483, 1000.178875554 from dual
6 ),
7 septest (tdec, bdec, ldec) as
8 (select 2, 2, 6 from dual)
9 select
10 b.total,
11 case when length(regexp_substr(b.total,'\d+$')) > s.tdec then 'Not OK'
12 else 'OK'
13 end total_ok,
14 --
15 b.balance,
16 case when length(regexp_substr(b.balance,'\d+$')) > s.bdec then 'Not OK'
17 else 'OK'
18 end balance_ok,
19 --
20 b.loan,
21 case when length(regexp_substr(b.loan,'\d+$')) > s.ldec then 'Not OK'
22 else 'OK'
23 end loan_ok
24 from big b cross join septest s;
TOTAL TOTAL_OK BALANCE BALANCE_OK LOAN LOAN_OK
---------- ---------- ---------- ---------- ---------- ----------
48528,64 OK 45428,64 OK 100,64 OK
135082,54 OK 1895082,11 OK 88999,1165 OK
349,1123 Not OK 5249,1483 Not OK 1000,17888 Not OK
SQL>
Lines #1 - 8 represent sample data; you already have that. Query you actually need begins at line #9.

Using loop to insert values from one table to another

I have the following table named screening_plan:
plan_id movie_id plan_start_day plan_end_day plan_min_start_hh24 plan_max_start_hh24 screenings
1 1 1/06/2015 28/06/2015 9 17 5
2 2 1/06/2015 28/06/2015 9 22 4
3 3 1/06/2015 28/06/2015 9 22 5
4 4 1/06/2015 28/06/2015 9 17 4
And another tables theatre:
THEATRE_ID THEATRE_DESCRIPTION THEATRE_TOTAL_ROWS
1 2
2 2
3 3
4 2
There is a total of 18 screenings per day. I have to insert the details in the screening table as follows:
screening_id plan_id theatre_id screening_date screening_start_hh24 screening_start_mm60
1 1 3 1/06/2015 9 0
2 1 3 1/06/2015 11 30
3 1 3 1/06/2015 14 0
4 1/06/2015
plan_id is a foreign key referring table screening and theatre_id is a foreign key referring table theatre.
Each movie should be screened as per the screening number is defined
in the table screening_plan.
There is a break of 30 minutes between 2 consecutive screenings in
the same theatre.
The screening_start_hh24 should be less than plan_max_start_hh24.
Please note that the number of screenings for the first movie won't
fit into the provided time interval,so the second screening should be done
in an alternate theatre(preferably in theatre_id=2 starting from 11:30).
Each movie has a lenght of 2 hours.
I am stuck with this since yesterday. Tried doing it using the If-Else block, but that requires defining every condition. How can I do this using a loop?Please help.
My code(I have skipped the declaration part here):
BEGIN
SELECT plan_id INTO s_plan_id FROM screening_plan WHERE plan_id=1;
SELECT theatre_id INTO s_theatre_id FROM theatre WHERE theatre_id=1;
SELECT PLAN_START_DATE INTO s_screening_date FROM screening_plan WHERE plan_id=1;
SELECT Count(*) INTO s_count_theatre_id FROM screening;
IF s_count_theatre_id = 0
THEN
s_screening_start_hh24:=9;
s_screening_start_mm60:=0;
ELSIF s_count_theatre_id >0 AND s_count_theatre_id <=4
THEN
s_screening_start_hh24:=11 ;
s_screening_start_mm60:=30 ;
ELSE
Dbms_Output.put_line('---');
END IF;
INSERT INTO screening (plan_id, theatre_id, screening_date, screening_start_hh24, screening_start_mm60)
VALUES( s_plan_id,
s_theatre_id,
s_screening_date,
s_screening_start_hh24,
s_screening_start_mm60);
END;
There should be a total of 18 record in the table screening.5 for movie_id=1, 4 for movie_id=2, 5 for movie_id=3 and 4 for movie_id=3.

update from temp table to original table

I have two tables one is original table and second one is temp table. Temp table having the correct record. Unique column is cust_id. My table structure is
Customer table
cust_id amount
12 100
13 120
14 130
15 250
20 70
25 110
28 900
temp table
cust_id amount
12 300
13 190
14 110
15 240
20 30
25 210
28 500
I want to update the record from temp table to customer orignal table using customer id.
It can be done using merge statement.
merge into original_table ot
using temp_table tp
on (ot.cust_id = tp.cust_id)
when matched
then update set ot.amount = tp. amount

Resources