How to update two tables together in Oracle? - java

Query :
UPDATE TABLE_ONE
SET DATE=?, URL=?, TYPE=?, STATE=?, FEE=?, NAME=?, STATUS=?
WHERE ID=?";
Another table TABLE_TWO has columns - NAME, ID, FEE, STATUS, TOTAL,I want that on running update all above fields specified in query plus FEE, STATUS of TABLE_TWO gets updated together. I'm using Spring.

You can use trigger for say Table1 & write a trigger if any update on table 1 call trigger to update the Table 2 data.
it starts like..
create or replace TRIGGER trigger_name
after insert or update on Table1
for each row
...
For complete trigger refer (https://www.tutorialspoint.com/plsql/plsql_triggers.htm)

You can't update 2 tables (more than one) in one statement, instead use 2 statements and call them inside method annotated with #Transactional
#Transactional
public void updateTables() {
updateTableOne();
updateTableTwo();
}
commit will happen when method exists for both tables.
See more about using #Transactional in Spring
Other option is calling oracle procedure
Spring provides various ways of abstractions on JDBC to call database stored procedures.
Example
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate)
.withProcedureName("MOVE_TO_HISTORY")

Solution 1: You can add both update statements in PLSQL procedure/function and execute the same in java code
Solution 2: You can add both update statements in a function and invoke the same

Oracle way of doing that is an instead-of trigger on a view.
Here's an example based on Scott's schema.
First, I'll create a view as a join of two tables, EMP and DEPT (that's where updating two tables together comes into a game):
SQL> create or replace view v_ed as
2 select d.deptno, e.empno, d.dname, e.ename, e.sal
3 from emp e join dept d on e.deptno = d.deptno;
View created.
Now, an instead-of trigger. I'm handling INSERT and UPDATE; you can add DELETE as well. It means that - when you insert into a view or update it, underlying tables will be the final target of those commands.
SQL> create or replace trigger trg_io_ed
2 instead of insert or update on v_ed
3 for each row
4 begin
5 if inserting then
6 insert into emp (deptno, empno, ename, sal)
7 values (:new.deptno, :new.empno, :new.ename, :new.sal);
8 insert into dept (deptno, dname)
9 values (:new.deptno, :new.dname);
10 elsif updating then
11 update emp set
12 deptno = :new.deptno,
13 ename = :new.ename,
14 sal = :new.sal
15 where empno = :new.empno;
16 update dept set
17 dname = :new.dname
18 where deptno = :new.deptno;
19 end if;
20 end;
21 /
Trigger created.
Some testing: insert:
SQL> insert into v_ed (deptno, empno, dname, ename, sal)
2 values (99, 100, 'test dept', 'Littlefoot', 1000);
1 row created.
SQL> select * From dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
99 test dept
SQL> select * From emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17.12.80 800 20
7499 ALLEN SALESMAN 7698 20.02.81 1600 300 30
7521 WARD 7698 22.02.81 1250 500
7566 JONES MANAGER 7839 02.04.81 2975 20
7654 MARTIN SALESMAN 7698 28.09.81 1250 1400 30
7698 BLAKE MANAGER 7839 01.05.81 2850
7782 CLARK MANAGER 7839 09.06.81 2450 10
7788 SCOTT ANALYST 7566 09.12.82 3000 20
7839 KING PRESIDENT 17.11.81 5000 10
7844 TURNER SALESMAN 7698 08.09.81 1500 0 30
7876 ADAMS CLERK 7788 12.01.83 1100 20
7900 JAMES CLERK 7698 03.12.81 950 30
7902 FORD ANALYST 7566 03.12.81 3000 20
7934 MILLER CLERK 7782 23.01.82 1300 10
100 Littlefoot 1000 99
15 rows selected.
SQL>
Update:
SQL> update v_ed set ename = 'Bigfoot' where empno = 100;
1 row updated.
SQL> select * From emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17.12.80 800 20
7499 ALLEN SALESMAN 7698 20.02.81 1600 300 30
7521 WARD 7698 22.02.81 1250 500
7566 JONES MANAGER 7839 02.04.81 2975 20
7654 MARTIN SALESMAN 7698 28.09.81 1250 1400 30
7698 BLAKE MANAGER 7839 01.05.81 2850
7782 CLARK MANAGER 7839 09.06.81 2450 10
7788 SCOTT ANALYST 7566 09.12.82 3000 20
7839 KING PRESIDENT 17.11.81 5000 10
7844 TURNER SALESMAN 7698 08.09.81 1500 0 30
7876 ADAMS CLERK 7788 12.01.83 1100 20
7900 JAMES CLERK 7698 03.12.81 950 30
7902 FORD ANALYST 7566 03.12.81 3000 20
7934 MILLER CLERK 7782 23.01.82 1300 10
100 Bigfoot 1000 99
15 rows selected.
SQL>
See if it helps.

Related

Moving Average from nested table using Oracle SQL

I'm trying to find the correct sql query based on the case below.
customer_id
unit_id
NAV
DATE
16
1254
10
2020-05-01
17
1253
20
2020-05-02
18
1253
30
2020-05-03
16
1254
20
2020-05-02
16
1254
30
2020-05-03
17
1253
20
2020-05-02
17
1255
30
2020-05-03
16
1254
20
2020-05-04
From the table above, the AVERAGE_NAV can be found by moving average since the first date unit purchased. So, if I want to find moving average NAV for spesific data of customer_id and unit_id from table ACCOUNTBALANCE, I use this query below.
SELECT
ACCBAL.CUSTOMER_ID,
ACCBAL.UNITTRUST_ID,
ACCBAL.INVACCT_ID,
ACCBAL.NAV,
AVG(ACCBAL.NAV)
OVER (
ORDER BY ACCBAL.BALANCEDATE
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
),
ACCBAL.CREATED_DATE
FROM WMS_UT_ACCOUNTBAL ACCBAL
WHERE
ACCBAL.CUSTOMER_ID=16 AND
ACCBAL.UNITTRUST_ID=1254
you can see the picture of the query in the link below.
query image
The result of the query is shown below.
customer_id
unit_id
NAV
DATE
Average_NAV
16
1254
10
2020-05-01
10
16
1254
20
2020-05-02
15
16
1254
30
2020-05-03
20
16
1254
20
2020-05-04
20
My question is, What is the query to find the average_NAV with all combined different customer_id and unit_id like this table below here.
customer_id
unit_id
NAV
DATE
average_NAV
16
1254
10
2020-05-01
10
17
1253
20
2020-05-02
20
18
1253
30
2020-05-03
30
16
1254
20
2020-05-02
15
16
1254
30
2020-05-03
20
17
1253
20
2020-05-02
20
17
1255
30
2020-05-03
30
16
1254
20
2020-05-04
20
the average_NAV must be based on the query result from the same customer_id and unitrust_id start from the first purchase. you can see that for customer_id=17 and unit_id=1255 has average_NAV=30 same as NAV since it's first purchase with those spesific customer_id and unit_id was 2020-05-03.
The main obstacle is how I can use where clause inside the outer SELECT because it's prohibited in oracle sql.
I have used CTE method (WITH) but still not what expected like below.
WITH ACCBAL (CUSTOMER_ID,UNITTRUST_ID,NAV, CREATED_DATE) AS
(SELECT ACCBAL1.CUSTOMER_ID, ACCBAL1.UNITTRUST_ID,
ACCBAL1.NAV, ACCBAL1.CREATED_DATE
FROM WMS_UT_ACCOUNTBAL ACCBAL1),
ACCBAL_AVERAGE_NAV (AVERAGE_NAV) AS
(SELECT AVG(ACCBAL2.NAV) OVER
(ORDER BY ACCBAL2.CREATED_DATE RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM WMS_UT_ACCOUNTBAL ACCBAL2
WHERE ACCBAL2.UNITTRUST_ID=ACCBAL.UNITTRUST_ID
AND ACCBAL2.CUSTOMER_ID=ACCBAL.CUSTOMER_ID)
SELECT * FROM ACCBAL,ACCBAL_AVERAGE_NAV;
The query above is not working because it gives error of invalid identidier in WHERE clause.
Anyone can help me? Truly Appreciated. Thank you
You can include the PARTITION BY clause before ORDER BY.
Tested on db<>fiddle
SELECT
ACCBAL.CUSTOMER_ID,
ACCBAL.UNITTRUST_ID,
-- ACCBAL.INVACCT_ID,
ACCBAL.NAV,
ACCBAL.CREATED_DATE,
AVG(ACCBAL.NAV)
OVER (
PARTITION BY ACCBAL.CUSTOMER_ID, ACCBAL.UNITTRUST_ID
ORDER BY ACCBAL.CREATED_DATE
)
FROM WMS_UT_ACCOUNTBAL ACCBAL;

Select the first duplicated element

I have 2 Classes in JAVA ( MODEL1 && MODEL2 )
As you can see here :
MODEL1_ID ACTN_DTE MODEL2_ID
---------- --------- --------------
1 14/11/19 18
1000 14/11/19 4
1001 14/11/19 19
1002 14/11/19 4
1003 14/11/19 4
1004 14/11/19 18
2000 14/11/19 5
I am trying to find a way with SQL Or HQL to get all elements from MODEL1 that have a list of MODEL2_ID , get only the first (min MODEL1_ID) MODEL1 per MODEL2_ID ( in case if it's duplucated ).
Exemple :
Input : MODEL2_ID in (18,4,19,5)
MODEL1_ID ACTN_DTE MODEL2_ID
---------- --------- --------------
1 14/11/19 18
1000 14/11/19 4
1001 14/11/19 19
2000 14/11/19 5
select MIN(MODEL1_ID) FROM table GROUP BY (MODEL2_ID)
It is possible that by "first" you mean the minimum actn_date and the question just has a useless sample of data (because all the values are the same).
If so, you can use aggregation with keep to get the first value by actn_date:
select model2_id, min(actn_date) as actn_date,
min(model1_id) keep (dense_rank first order by actn_date) as model1_id
from t
group by model2_id;

Selecting rownum/max(rownum) with jOOQ

I'm looking at a SQL query that uses Oracle's rownum pseudocolumn to select the row number as a fraction of the total rows:
ROWNUM/(MAX(ROWNUM) OVER())
I'm trying to accomplish the same thing with a query written via jOOQ. Is that possible?
I'm not sure I got your question right - is it that you need ?
SQL> select row_number() over(order by ename)/(count(*) over()) fraction from emp;
FRACTION
----------
.08333
.16667
.25000
.33333
.41667
.50000
.58333
.66667
.75000
.83333
.91667
1.00000
Also CUME_DIST analytic function can be useful:
SQL> SELECT ename, CUME_DIST()
2 OVER (ORDER BY ename) fraction
3 FROM emp
4 /
ENAME FRACTION
---------- ----------
ALLEN .08333
BLAKE .16667
CLARK .25000
FORD .33333
JAMES .41667
JONES .50000
KING .58333
MARTIN .66667
MILLER .75000
SMITH .83333
TURNER .91667
WARD 1.00000
While Dmitry's CUME_DIST() solution is probably better suited for the actual query, here's the ROWNUM solution in jOOQ, for the record:
// Qualified
DSL.rownum().div(DSL.max(DSL.rownum()).over());
// With static imports of DSL.*
rownum().div(max(rownum()).over());
See also: DSL.rownum()

Comparing rowset data in Java

I get two cached row sets of data from two tables; table1 and table2.
table1
OrgCode Name Amt FeeCode
1 John 100 R
1 Micheal 200 L
table2
OrgCode AgreementNo AddressNo CustomerNo FeeCode
1 111 211 555 R
1 222 212 666 L
1 333 213 777 P
I need to compare two cachedrow sets, and send the data (cached row set) table to JSP depending on the matching feecode in tables2.
The Sql formed for Cached row set for table-1 is dynamically formed,the same method is used by different classes,with return type cached row set
How might I do this?

select data from last 2 rows sql

Im using an odbc-jdbc bridge in my project and I need select 2 pieces of data from the database and save the data to 2 variables on the java side of my application. Here is an example of my table.
SITE_ID ------- DEV_ID ------- SCHEDULE_TIME ------- VALUE_ENUM ------- IDX
---------------------------------------------------------------------------
1 3000 09:30:00 1 1
1 3000 11:30:00 0 2
1 3000 12:00:00 1 3
1 3000 14:00:00 0 4
1 3000 18:30:00 1 5
1 3000 20:30:00 0 6
1 4000 05:00:00 1 1
1 4000 13:30:00 0 2
1 4000 16:30:00 1 3
1 4000 18:30:00 0 4
What I want to do is select SCHEDULE_TIME for the last 2 IDX's where DEV_ID is 3000, so I would like to save 18:30:00 and 20:30:00 in a variables, some examples of statements Ive tried are:
select SCHEDULE_TIME from ARRAY_BAC_SCH_Schedule order by IDX desc limit 1 where DEV_ID = 3000
select SCHEDULE_TIME from ARRAY_BAC_SCH_Schedule order by IDX desc limit (1,1) where DEV_ID = 3000
SELECT TOP 1 SCHEDULE_TIME FROM ARRAY_BAC_SCH_Schedule WHERE DEV_ID = 3000 ORDER BY IDX DESC
Right now Im just worrying about how to get the select statement to work in Query tool before I implement it in the java side. Thanks, Beef.
For SQL Server you should use
SELECT TOP 2 SCHEDULE_TIME from (select SCHEDULE_TIME FROM ARRAY_BAC_SCH_Schedule WHERE DEV_ID = 3000 ORDER BY IDX DESC) as inner
like Hemal told you.
Be careful with queries like
select TOP 2 SCHEDULE_TIME FROM ARRAY_BAC_SCH_Schedule WHERE DEV_ID = 3000 ORDER BY IDX DESC
because that is wrong. SQL Server does the top and then the order.
In PostgreSQL or MySQL you should use limit and the end of the query. The limit is after the where part.
In Oracle you should use rownum inside the where part.
Maybe I'm missing something. Is there a reason you wouldn't just run:
select SCHEDULE_TIME from ARRAY_BAC_SCH_Schedule order by IDX desc limit 2 where DEV_ID = 3000
This should return 2 rows, containing 20:30:00 and 18:30:00.
if it is mysql then
select SCHEDULE_TIME from ARRAY_BAC_SCH_Schedule where DEV_ID = 3000 order by IDX desc limit 2
I think
SELECT TOP 2 * from (select SCHEDULE_TIME FROM ARRAY_BAC_SCH_Schedule WHERE DEV_ID = 3000 ORDER BY IDX DESC) as inner
The specifics will vary a little based on your DB, but your query should look something like this:
SELECT TOP 2 SCHEDULE_TIME
FROM ARRAY_BAC_SCH_Schedule
WHERE DEV_ID = 3000
ORDER BY IDX Desc
Or, on one line:
SELECT TOP 2 SCHEDULE_TIME FROM ARRAY_BAC_SCH_Schedule WHERE DEV_ID = 3000 ORDER BY IDX Desc
You can do that with subquerys:
select * from array_bac_sch_schedule where (value_enum,idx) in (select value_enum,idx from array_bac_sch_schedule where dev_id=3000) order by schedule_time desc limit 2;
I took value_enum and idx as primary key.

Categories