Making an Oracle query between three tables using INNER JOIN - oracle

I'm working with a super inconsistent Oracle database and I need help to make a query.
Simplyfying the database to an example I have these three tables.
TABLE_F
------
id = 3
title = "Hello"
TABLE_M
------
id = 3
category = "val3"
flid = 5
TABLE_X
------
id = 3
body = "How are you?"
flid = 30
id = 3
body= "Bye bye"
flid = 35
I want to make a query to get the following result:
id | title | mat | BODY | OTHER
------------------------------------------
3 helllo val3 How are you? Bye bye
My query is:
SELECT
TABLE_F.title,
TABLE_M.category,
TABLE_X.body as BODY
FROM TABLE_F
INNER JOIN TABLE_M
ON TABLE_F.id=TABLE_M.id
INNER JOIN TABLE_X
ON TABLE_F.id=TABLE_X.id
WHERE TABLE_M.flid=5 AND TABLE_X.flid=30;
Where I get:
id | title | mat | BODY
--------------------------------
3 helllo val3 How are you?
I need to add to the query the TABLE_X.body as OTHER (which contains the "Bye bye" string), BUT I can't do it as I'm filtering witd flid=30 in order to get the body.
It's not my database and I can't change the design. I need to get that desired output with one query (which I dont know if it's possible).
Thanks in advance.

Join table_x two times using alias
SELECT_F.id,
TABLE_F.title,
TABLE_M.category mat,
TABLE_X.body BODY,
Y.body OTHER BODY,
FROM TABLE_F
INNER JOIN TABLE_M ON TABLE_F.id=TABLE_M.id
INNER JOIN TABLE_X ON TABLE_F.id=TABLE_X.id AND TABLE_X.flid=30
INNER JOIN TABLE_X Y ON TABLE_F.id=Y.id AND Y.flid=35

Related

How to pass multiple values to UPDATE or SELECT COUNT(*) statement

I am trying to do a update a record.
Table name is customer
id | name | address | state
---+---------+------------+-------------------------
1 | John | 123 main st | TX
2 | Jack | 678 John st | NJ
3 | Bet | 987 Tx st | NY
4 | Maddy| 9812 Hudson st | CA
5 | ABCD | 9813 Mainly st | PA
My query is like below
UPDATE CUSTOMER c SET c.state = 'CA' WHERE c.id IN (idList);
Where idList is a localVariable that I created and it returns a list of id like 1,3,5
The query is working if do it like
UPDATE CUSTOMER c SET c.state = 'CA' WHERE c.id IN (1,3,5);
It is updating the respective records to CA.
But if I use it as
UPDATE CUSTOMER c SET c.state = 'CA' WHERE c.id IN (idList);
I get the below error. I don't want to pass the list directly as the list might change. I am getting the list of ids using a different command where it returns and assigns to idList as 1,3,5
Error:
ORA-01722: invalid number
ORA-06512: at line 35
01722. 00000 - "invalid number"**
How to solve this? I am writing it as a stored procedure.
I guess idList is a comma separated string with all the ids that you want to update.So what is happening is that the operator IN compares each id with that string and since this comparison can't succeed in any case you get an error.
What you can do instead is use the LIKE operator:
UPDATE customer
SET "state" = 'CA'
WHERE ',' || idList || ',' LIKE '%,' || "id" || ',%'
See the demo.
You may create parameterized query string and pass values like,
UPDATE CUSTOMER c SET c.state = 'CA' WHERE c.id IN (:idList);
You can't substitute a text variable for a list of values - it's simply not allowed. You're going to have to use dynamic SQL:
EXECUTE IMMEDIATE 'UPDATE CUSTOMER c SET c.state = ''CA'' WHERE c.id IN (' || idList || ')';

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 Join Two Queries With Distinct Answer

I need help in linking two tables together to bring back data as I need.
I have two queries:
The first is as follows:
SELECT
POI.PO_ID as PO_ID, SUM(POI.INV_QTY) AS INV_QTY, POI.INV_NUMBER,
PO.SUP_SUP_ID AS SUPPLIER
FROM TABLE1 POI, PUR_ORDS PO
WHERE POI.PO_ID = '56886' AND POI.PO_ID = PO.PO_ID
GROUP BY POI.PO_ID, POI.INV_NUMBER, PO.SUP_SUP_ID
ORDER BY POI.INV_NUMBER ASC
The Results of this query are as follows:
PO_ID|INV_QTY|INV_NUMBER|SUPPLIER
---------------------------------
56886| 105|INV1 |SUP1
56886| 106|INV2 |SUP1
The second query I have is this:
SELECT
DIL.PO_PO_ID, sum(DIL.ACPTD_QTY) as ACPTD_QTY,
DIL.DLVD_DLVY_NUMB AS DEL_NUM
FROM TABLE2 DIL
where DIL.PO_PO_ID = '56886'
GROUP BY PO_PO_ID, DIL.DLVD_DLVY_NUMB
order by del_num
The Results of this query are as follows:
PO_PO_ID|ACPTD_QTY|DEL_NUM
--------------------------
56886| 105| 1
56886| 106| 2
Now I am attempting to join the two tables, but I get multiple values appearing, using the following:
SELECT DISTINCT(PO_ID), INV_NUMBER, INV_QTY, SUPPLIER, ACPTD_QTY, DEL_NUM
FROM
(SELECT
SELECT POI.PO_ID as PO_ID, SUM(POI.INV_QTY) AS INV_QTY,
POI.INV_NUMBER, PO.SUP_SUP_ID AS SUPPLIER
FROM TABLE1 POI, PUR_ORDS PO
WHERE POI.PO_ID = '56886'
AND POI.PO_ID = PO.PO_ID
GROUP BY POI.PO_ID, POI.INV_NUMBER, PO.SUP_SUP_ID
ORDER BY POI.INV_NUMBER ASC) POINET
INNER JOIN
(SELECT DIL.PO_PO_ID, sum(DIL.ACPTD_QTY) as ACPTD_QTY,
DIL.DLVD_DLVY_NUMB AS DEL_NUM
FROM TABLE 2 DIL
where DIL.PO_PO_ID = '56886'
GROUP BY PO_PO_ID, DIL.DLVD_DLVY_NUMB
order by DEL_NUM) DILV
ON DILV.PO_PO_ID = POINET.PO_ID
GROUP BY PO_ID, INV_NUMBER, INV_QTY, SUPPLIER, ACPTD_QTY, DEL_NUM
ORDER BY INV_NUMBER
However the dataset I get is this:
PO_ID|INV_NUMBER |INV_QTY|SUPPLIER|ACPTD_QTY|DEL_NUM
-----------------------------------------------------
56886|K-101/2014-15| 105|SUP1 | 105| 1
56886|K-101/2014-15| 105|SUP1 | 106| 2
56886|K-107/2014-15| 106|SUP1 | 105| 1
56886|K-107/2014-15| 106|SUP1 | 106| 2
However I need it show the following:
PO_ID|INV_NUMBER |INV_QTY|SUPPLIER|ACPTD_QTY|DEL_NUM
------------------------------------------------------
56886|K-101/2014-15| 105|SUP1 | 105| 1
56886|K-107/2014-15| 106|SUP1 | 106| 2
What do I need to do, to tweak my query?
Any help would be much appreciated.
I think you just need to modify your join statement to join on both columns
ON DILV.PO_PO_ID = POINET.PO_ID
AND DILV.INV_QTY = POINET.ACPTD_QTY
Actually, you can probably leave out the PO_ID, because I it's the same in both subqueries:
i.e. Just do this (on the third last line):
ON DILV.INV_QTY = POINET.ACPTD_QTY

How to append result from select to resultset?

I have the following tables:
Table 1 - NODES (I access it through a DB_LINK):
SITE_ID LATITUDE LONGITUDE
ABC123 21.018 -89.711
CDE456 20.35 -87.349
FGH789 20.258 -87.406
ABB987 18.54 -88.302
CFF546 18.542 -88.273
GHT553 18.52 -88.311
Table 2 - LINKS
ID SITE_A SITE_B STATUS NAME LINK_TYPE REGION ---> Many other fields
1 ABC123 GHT553
2 FGH789 CFF546
3 CDE456 ABC123
4 CFF546 GHT553
Table 3 - RESULT (This is what I want to achieve) - No matter the order
LINK_ID SITE_A_ID LAT_SITE_A LON_SITE_A SITE_B_ID LAT_SITE_B LON_SITE_B
1 ABC123 21.018 -89.711 GHT553 18.52 -88.311
2 FGH789 20.258 -87.406 CFF546 18.542 -88.273
3 CDE456 20.35 -87.349 ABC123 21.018 -89.711
4 CFF546 18.542 -88.273 GHT553 18.52 -88.311
(Plus several other fields, which means no trouble for me)
This is what I have tried:
SELECT RES2.*, SAM2.LATITUDE LAT_SITE_B, SAM2.LONGITUDE LON_SITE_B FROM(
SELECT RES1.*, NOD.LATITUDE LAT_SITE_A, NOD.LONGITUDE LON_SITE_A FROM(
SELECT ID, SITE_A, SITE_B, STATUS, NAME, LINK_TYPE FROM LINKS
WHERE SITE_A IS NOT NULL AND SITE_B IS NOT NULL AND REGION IN (8,6)
)RES1, NODES#NODES_DBLINK NOD WHERE RES1.SITE_A = NOD.SITE_ID
)RES2, NODES#NODES_DBLINK NOD2
WHERE RES2.SITE_B = NOD2.SITE_ID;
Until the SELECT RES1.\*, everything works fine, but when I add the SELECT RES2.\*, it takes too long without returning anything.
From the textual part of your question, this query will generate the result you want:
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN nodes#nodes_dblink node_a ON (links.site_a = node_a.site_id)
INNER JOIN nodes#nodes_dblink node_b ON (links.site_b = node_b.site_id)
ORDER BY links.id;
From the query you posted it seems you have some other criteria to include too which might mean you want something more like this:
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN nodes#nodes_dblink node_a ON (links.site_a = node_a.site_id)
INNER JOIN nodes#nodes_dblink node_b ON (links.site_b = node_b.site_id)
WHERE links.site_a IS NOT NULL
AND links.site_b IS NOT NULL
AND links.region IN (8, 6)
ORDER BY links.id;
Hope it helps...
EDIT:
If your DB link is an issue, try to return only the data you're going to need over the link in advance either by creating a view on the remote DB or a materialised view on the local DB.
If that isn't practical then check the relative explain plans for the query above against this one and see if it is any better:
WITH node_data
AS (SELECT site_id,
latitude,
longitude
FROM nodes#nodes_dblink node
WHERE EXISTS (SELECT 1
FROM links
WHERE links.site_a = node.site_id
OR links.site_b = node.site_id))
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN node_data node_a ON (links.site_a = node_a.site_id)
INNER JOIN node_data node_b ON (links.site_b = node_b.site_id)
WHERE links.site_a IS NOT NULL
AND links.site_b IS NOT NULL
AND links.region IN (8, 6)
ORDER BY links.id;

Resources