Oracle subquery subtraction. - oracle

I'm trying to subtract a value from one table from a different table example if I have two tables like attached:
I want to update the numbers by subtractracting from QD in table QI so the new table will be
QI:
a 900
b 800
c 700
what's the best way to do this? Thanks in advance

Assuming there will only be 0 or 1 qd row per col1 value:
update qi
set col2 = col2 - (select col2 from qd where qd.col1 = qi.col1)
where exists (select null from qd where qd.col1 = qi.col1);
The where exists clause is to prevent updating qi rows that have no qd counterpart.

Better dont use subquery on this case. Use like this:
select I.COL1,
(I.COL2 - D.COL2) as COL2
from TABLE_QI I
left join TABLE_QD D on D.COL1 = I.COL1;
Here is the SQL Fiddle

Related

I have a SQL table which consists of employee details and I have 3 update statements that works separately and want to merge it to 1 single starment

I have a SQL table which consists of employee details and my problem is I have three separate updates statements and want to club it together so that I can create a procedure which updates the table in such a way that it shows the salary including the bonus and the latest salary date which makes use of another bonus table
1]update employee_1 set employee_1.salary=(select sum(bonus_1.bonus_amount)from bonus_1 where employee_1.employee_id=bonus_1.employee_id GROUP by bonus_1.employee_id);
2]update employee_1 set employee_1.last_bonus_date=(select max(bonus_1.bonus_date)from bonus_1 where employee_1.employee_id=bonus_1.employee_id GROUP by bonus_1.employee_id);
3]update employee_1 set salary=salary+old_salary;
Basically need to combine these update statements so that I can use it in a procedure
You should've posted tables' description and sample data that illustrate the problem.
To me, it looks as if a single MERGE statement does the whole job (i.e. combines your 3 queries into 1):
merge into employee_1 a
using bonus_1 b
on (a.employee_id = b.employee_id)
when matched then update set
a.salary = a.salary + b.bonus_amount,
a.last_bonus_date = b.bonus_date;
You can use a MERGE statement and perform the aggregation in the USING clause:
MERGE INTO employee_1 e
USING (
SELECT employee_id,
SUM(bonus_amount) AS total_bonus,
MAX(bonus_date) AS last_date
FROM bonus_1
GROUP BY employee_id
) b
ON (e.employee_id = b.employee_id)
WHEN MATCHED THEN
UPDATE
SET salary = e.salary + b.total_bonus,
last_bonus_date = b.last_date;

Restructure Inline view

SELECT MAX(column1)
FROM table1 B , table2 A, table3 H
WHERE B.unit=A.unit
AND B.value=A.value
AND B.unit=H.unit
AND B.value=H.value
AND A.number=1234
Can someone help me to restructure this query in inline view?
SAMPLE
Table1
------
Value Unit
001 A1
002 B1
003 C2
002 A1
Table2
--------
Value Unit Number
001 B4 11
002 B1 1234
004 B1 22
TABLE3
-------
VALUE UNIT NUMBER COLUMN1
001 B4 11 555
002 B1 1234 557
002 B1 1234 559
OUTPUT
------
MAX(C0LUMN1)
-----------
559
In your query there is no need for inlineview :-
if that is rewritten in inlineview it will be like
Select Max(Column1)
From (Select Value,Unit From Table1)B,
(Select Value,Unit,Number From Table2)A,
Table3 as H
Where B.Unit=A.Unit
And B.Value=A.Value
AND B.unit=H.unit
And B.Value=H.Value
AND A.number=1234;
Below is the example when to use inline view hope this help!!!
An inline view is a SELECT statement in the FROM clause. As mentioned in the View section, a view is a virtual table that has the characteristics of a table yet does not hold any actual data. In an inline view construct, instead of specifying table name(s) after the FROM keyword, the source of the data actually comes from a view that is created within the SQL statement. The syntax for an inline view is,
SELECT "column_name" FROM (Inline View);
When should we use inline view? Below is an example:
Assume we have two tables: The first table is User_Address, which maps each user to a ZIP code; the second table is User_Score, which records all the scores of each user. The question is, how to write a SQL query to find the number of users who scored higher than 200 for each ZIP code?
Without using an inline view, we can accomplish this in two steps:
Query 1
CREATE TABLE User_Higher_Than_200
SELECT User_ID, SUM(Score) FROM User_Score
GROUP BY User_ID
HAVING SUM(Score) > 200;
Query 2
SELECT a2.ZIP_CODE, COUNT(a1.User_ID)
FROM User_Higher_Than_200 a1, User_Address a2
WHERE a1.User_ID = a2.ZIP_CODE
GROUP BY a2.ZIP_CODE;
In the above code, we introduced a temporary table, User_Higher_Than_200, to store the list of users who scored higher than 200. User_Higher_Than_200 is then used to join to the User_Address table to get the final result.
We can simplify the above SQL using the inline view construct as follows:
Query 3
SELECT a2.ZIP_CODE, COUNT(a1.User_ID)
FROM
(SELECT User_ID, SUM(Score) FROM
User_Score GROUP BY User_ID HAVING SUM(Score) > 200) a1,
User_Address a2
WHERE a1.User_ID = a2.ZIP_CODE
GROUP BY a2.ZIP_CODE;
There are two advantages on using inline view here:
We do not need to create the temporary table. This prevents the database from having too many objects, which is a good thing as each additional object in the database costs resources to manage.
We can use a single SQL query to accomplish what we want
Notice that we treat the inline view exactly the same as we treat a table. Comparing Query 2 and Query 3, we see that the only difference is we replace the temporary table name in Query 2 with the inline view statement in Query 3. Everything else stays the same.
Inline view is sometimes referred to as derived table. These two terms are used interchangeably.
I need to show column from other table that have the max column value
SELECT MAX( H.column1 ) AS max_column1,
MAX( A.number ) KEEP ( DENSE_RANK LAST ORDER BY H.column1 ) AS max_number
FROM table1 B
INNER JOIN table2 A
ON ( B.unit = A.unit AND B.value = A.value )
INNER JOIN table3 H
ON ( B.unit = H.unit AND B.value = H.value )
WHERE A.number=1234

How to update table1 field by using other table and function

I have two table and one function,
Table1 contains shop_code,batch_id,registry_id
shop_code| batch_id|registry_id
123 | 100 |12
124 | 100 |13
125 | 100 |12
Table2 contains shop_code,shop_name
shop_code| shop_name
123 | need to populate
124 | need to populate
125 | need to populate
Function1 take parameter registry_id from table1 and returns shop_name
Table2 shop_name is empty I want to populate against the shop_code.
I have tried my best but all effort is gone in vain.
It will be great if someone can help I am using Oracle.
I tried below code but giving error on from keyword
update TABLE2 set T2.SHOP_NAME = T.SHOP_NAME
from(
select GET_shop_name(t1.registry_id) as shop_name ,
t1.shop_code shop_code
from TABLE1 T1
) t where t.shop_code = t1.shop_code;
I am not entirely 100% sure if I got your question right, but I believe you want something like
update
table2 u
set
shop_name = (
select
get_shop_name(t1.batch_id)
from
table1 t1
where
t1.chop_code = u.shop_code
);
can you try this approach try to put inner query to get shop name value; I have not tested it but I think approach will work for you.
update TABLE2 T2
set T2.SHOP_NAME =
(select GET_shop_name(t1.batch_id, t1.shop_code) from table1 t1 wehre t1.shop_code = t2.shop_code)
where T2.shop_name is null
You want the MERGE statement.
Something like this might work:
MERGE INTO TABLE2 t2
USING (
SELECT GET_shop_name(t1.batch_id) AS shop_name ,
t1.shop_code shop_code
FROM TABLE1 T1 ) t1
ON (t2.shop_code = t1.shop_code)
WHEN MATCHED THEN
UPDATE SET t2.shop_name = t1.shop_name
;
You'll have to excuse if the exact code above doesn't work I don't have SQL Dev where I am right now for syntax details. :)

Oracle Query : Single update statement

I need to code an Oracle Query for the below logic and any help is appreciated.
I have a table with 8 columns and out of that need to consider 3 column for the a specific business logic.
Table data (with the 3 columns)
A B C
071699 01 I
071699 01W
071699 02W
071699 01W I
071699 02W
more rows.
Amount of data varies depending upon case, meaning it could be one or more rows per column A-B combination and usually out of these
column C is populated for at least 1 combination.
This table has over 100K of distinct A values.
Logic I need to implement:
Check - for a specific A value, how many combinations we have (A-B).
For a specific A: Check if any combination (A-B) is populated with column C data.
Take the value from the populated C column and update the same table (for the other combination of same A)
Data before (only showing specific rows)
A B C
071699 01 I
071699 01W
071699 02W
Data After Query
A B C
071699 01 I
071699 01W I
071699 02W I
I have a SQL server query doing this logic in a single query but not working in Oracle and I am getting error,"Single row query returning more than one row"
SQL Server Query
update c
set c.colC = u.colC
from data_table u
join data_table c on u.colA = c.colA and u.colB <> c.colB
and u.colB = (select MIN(colB) from data_table
where colA = u.colA and colC is not null)
and u.colC is not null and c.colC is null
Any help is appreciated to write similar oracle version.
Oracle doesn't allow joins in update queries unless you have a unique column which guarantees a 1-1 mapping which definitely doesn't apply in your case. So about the best you can do here is a nested subquery. It ain't pretty but it will work. I wasn't able to completely match up the logic you said you needed to implement with the logic that was in the SQL Server update statement, so I went with the statement.
UPDATE data_table u
SET u.COLC =(
SELECT c.ColC
FROM data_table c
WHERE c.ColA = u.ColA
and c.ColB =(
SELECT MIN( ColB )
FROM data_table
WHERE ColA = c.ColA
AND ColC IS NOT NULL
)
)
where u.ColC is null;
I tried various ways to do this task in a single query but not able to achieve that due to Oracle limitations, below is the solution worked for me:
I split the query into two parts - one doing insert statement and another with update.
First query : Here I am inserting the rows into another temp table, logic - get distinct rows per colA - ColC where colC is polulated.
Use the tmp table created in the step 1, to update the main data table by join on colA.
If anyone has better solution, then please send your response and I'll surely try it.
I resolved this issue with the set based coding after trying various methods like spliting into two tmp tables, cursor, etc, below is the sample code :
This query is 3-5X faster than any other solution.
UPDATE data_table a SET C = (
WITH comp AS (
SELECT DISTINCT A, C FROM data_table a
WHERE B = (SELECT MIN(B) FROM data_table
WHERE A = a.A
AND C IS NOT NULL)
)
SELECT
CASE
when a.C IS NULL THEN c.C
when a.C IS NOT NULL THEN a.C
END
FROM comp c
WHERE a.A = c.A AND c.C IS NOT NULL
);

Extracting different fields and tables ORACLE R12 TABLES

I have a problem of joining the tables of Oracle r12 tables. I have tried something like this..
SELECT
part.party_name,
custA.account_number,
headAll.cust_po_number,
headAll.order_number,
trans.NAME,
headAll.ordered_date,
sales.person_name,
headAll.flow_status_code,
items.segment1,
lineAll.ordered_quantity,
lineAll.order_quantity_uom,
lineAll.unit_selling_price,
lineAll.tax_code
FROM
oe_order_headers_all headAll,
oe_order_lines_all lineAll,
hz_cust_accounts custA,
hz_parties part,
oe_transaction_types_tl trans,
hz_person_profiles sales,
mtl_system_items_b items
WHERE
headAll.Header_ID = lineAll.Header_ID
AND custA.Application_ID = part.Application_ID
AND custA.Application_ID = sales.Application_ID
AND items.inventory_item_id = lineAll.inventory_item_id;
It is running but I know it is wrong because it is multiplying tables. Any Ideas of r12 tables in Oracle and combining this sample r12 tables?
-oe_order_headers_all
-oe_order_lines_all
-hz_cust_accounts
-hz_parties
-oe_transaction_types_tl
-hz_person_profiles
-mtl_system_items_b
I Tried this..
Updated:
from oe_order_headers_all headAll
INNER JOIN
oe_order_lines_all lineAll
ON headAll.Header_ID = lineAll.Header_ID
INNER JOIN
hz_cust_accounts custA
ON headAll.sold_to_org_id = custA.cust_account_id
INNER JOIN
hz_parties part
ON custA.party_id = part.party_id
INNER JOIN
oe_transaction_types_tl trans
ON headAll.order_type_id = trans.transaction_type_id
INNER JOIN
hz_person_profiles sales
ON part.party_id = sales.party_id
INNER JOIN
mtl_system_items_b items
ON items.inventory_item_id = lineAll.inventory_item_id
And I Tried Where Clause
where headAll.Header_ID = lineAll.Header_ID AND headAll.order_type_id = trans.transaction_type_id AND custA.party_id = part.party_id
AND part.party_id = sales.party_id AND headAll.sold_to_org_id = custA.cust_account_id AND items.inventory_item_id = lineAll.inventory_item_id;
Still multiplying..
Forget about having Oracle R12 suite. In general any Oracle engine will behave like this.
Let me show you some examples.
TABLE A
- COL1 PK1
- COL2 PK1
- COL3
TABLE B
- COL4 PK2
- COL5 PK2
- COL6
TABLE C
- COL7
- COL8 -PK3
- COL9 -PK3
In this model, whenever we join any tables unless you join on their key combinations or based on the rule that for any given row you retrieve a maximum of one row from the other table.
SELECT A.COL1
FROM TABLEA, TABLEB
WHERE COL1 = COL4
AND COL2 = COL5;
OR in ANSI syntax
SELECT A.COL1
FROM TABLEA
JOIN TABLEB ON COL1 = COL4 AND COL2 = COL5;
So this can be extended on the third table.
SELECT A.COL1
FROM TABLEA, TABLEB, TABLEC
WHERE COL1 = COL4
AND COL2 = COL5
AND COL1 = COL8
AND COL2 = COL9;
PS: The assumption is that the combined primary key on both the tables will always provide one row for the other.
You need to extend your ON clauses to include a condition so that for each entry in TABLE A there is only one entry in TABLE B that matches the condition and that for each entry in TABLE B there is only one entry in TABLE C
You can always try to join tables one by one and keep the query building until and unless you done violate the thumb rule (said above).
If, I change the join condition and any table duplicates while performing the same, then the same will be propagated to the subsequent joins.
There are not all relations between tables. Alias trans isn't related at all, groups headAll, lineAll, items and custA, part, sales are separated. In this case rows will be joined with default cross join.
Add conditions in the WHERE clause:
AND headAll.order_type_id = trans.transaction_type_id
AND headAll.sold_to_org_id = custA.cust_account_id
Please see this example from Oracle tutorial: Query to get the OM Sales Order summary details

Resources