Join two tables in Oracle - sql

I need something like:
select *
from table1
where {if PKID = MasterPKID - (that PKID should not be present as refNo in table2)}.
ie- 652 should not be present in Table2
I am totally clueless.
Can we achieve it in one query?

Use Not exists
select *
from table1 a
where PKID = MasterPKID
and not exists (select 1 from table2 b where a.PKID = b.refno)

Try any of these!!
If MaterPKID can contain NULL Values then go for not exists
select *
from table1 a
where PKID = MasterPKID
and not exists (select 1 from table2 b where a.PKID = b.refno)
else go with not in
select *
from table1 a
where PKID = MasterPKID
and PKID not in (select REFNO from table2)

Related

Matching multiple columns in one join

I have two tables:
Table 1
item_name | assocID_1 | assocID_2 | assocID_3
ball 123 456 789
Table 2
assoc_key assoc_value
123 red
456 white
789 blue
Am I able to create an output of:
ball red white blue
With only one join? I understand I can just join the tables multiple times to easily get this result, but in my actual tables there are much more than 3 columns, and the app I'm using can only support 4 joins per query apparently.
Many thanks for any help.
If you don't care about performance, you can do:
select t1.item_name,
max(case when t2.assoc_key = t1.assocID_1 then t2.assoc_value end),
max(case when t2.assoc_key = t1.assocID_2 then t2.assoc_value end),
max(case when t2.assoc_key = t1.assocID_3 then t2.assoc_value end)
from table1 t1 join
table2 t2
on t2.assoc_key in (t1.assocID_1, t1.assocID_2, t1.assocID_3)
group by t1.item_name;
You can also use subqueries. If we assume that there is only one matching row in table2:
select t1.item_name,
(select t2.assoc_value from table2 t2 where t2.assoc_key = t1.assocID_1),
(select t2.assoc_value from table2 t2 where t2.assoc_key = t1.assocID_2),
(select t2.assoc_value from table2 t2 where t2.assoc_key = t1.assocID_3)
from table1 t1;
If there can be more than one match, you can arbitrarily choose one of them using aggregation functions:
select t1.item_name,
(select max(t2.assoc_value) from table2 t2 where t2.assoc_key = t1.assocID_1),
(select max(t2.assoc_value) from table2 t2 where t2.assoc_key = t1.assocID_2),
(select max(t2.assoc_value) from table2 t2 where t2.assoc_key = t1.assocID_3)
from table1 t1;
I do not think you need a join here. You just need to look up which you can do in the SELECT statement directly. Here is an implementation in SQL Server (In Sample Data preparation code, if you are using version older than SQL Server 2016, please replace the DROP TABLE IF EXISTS with older way of doing the same)
DDL and Test Data:
DROP TABLE IF EXISTS Table1
SELECT item_name = 'ball'
,assocID_1 = 123
,assocID_2 = 456
,assocID_3 = 789
INTO Table1
DROP TABLE IF EXISTS Table2
SELECT assoc_key = 123
,assoc_value = 'red'
INTO Table2
UNION ALL
SELECT assoc_key = 456
,assoc_value = 'white'
UNION ALL
SELECT assoc_key = 789
,assoc_value = 'blue'
SELECT * FROM Table1
SELECT * FROM Table2
1. Brute Force Approach:
SELECT item_name = T1.item_name
,(SELECT TOP 1 assoc_value FROM Table2 WHERE assoc_key = T1.assocID_1)
,(SELECT TOP 1 assoc_value FROM Table2 WHERE assoc_key = T1.assocID_2)
,(SELECT TOP 1 assoc_value FROM Table2 WHERE assoc_key = T1.assocID_3)
FROM Table1 T1
2. Dynamically Building the Query For Ease And Then Executing It. With this approach Number of Columns Would Not Be a Concern:
DECLARE #SQL NVARCHAR(MAX) = 'SELECT item_name = T1.item_name '
SELECT #SQL += '
,(SELECT TOP 1 assoc_value FROM Table2 WHERE assoc_key = T1.'+COLUMN_NAME+')'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo' -- provide your proper schema name here
AND TABLE_NAME = 'Table1'
AND COLUMN_NAME <> 'item_name' -- provide the columns you want to avoid doing lookups
ORDER BY ORDINAL_POSITION
SET #SQL+='
FROM Table1 T1 '
PRINT #SQL
EXEC sp_executesql #statement=#SQL
3. Combination of UNPIVOT, JOIN and PIVOT
SELECT item_name, [assocID_1], [assocID_2], [assocID_3] -- you can dynamically build the select list like above example if you need
FROM
(
SELECT IQ.item_name, IQ.assocId, T2.assoc_value
FROM (
SELECT UNP.item_name, UNP.assocId, UNP.Value
FROM Table1 T1
UNPIVOT
(
Value FOR assocId IN ([assocId_1], [assocId_2], [assocId_3]) -- you can dynamically build this column list like above example if you need
) UNP
) IQ
INNER JOIN Table2 T2
ON IQ.Value = T2.assoc_key
) OQ
PIVOT
(
MAX(assoc_value)
FOR associd IN ([assocID_1], [assocID_2], [assocID_3]) -- you can dynamically build this column list like above example if you need
) PV
select item_name, decode(ASSOCID_1,(select assocID_1 from t1 ), (select assoc from t2 where assoc_key =aa.assocID_1),null ) ,
decode(ASSOCID_2,(select assocID_2 from t1 ) , (select assoc from t2 where assoc_key =aa.assocID_1),null ),
decode(ASSOCID_3,(select assocID_3 from t1 ), (select assoc from t2 where assoc_key =aa.assocID_1),null ) from t1 aa

Select from table only with no records on the second table

I have the following tables
TABLE1 (ID_OWNER, NAME)
1,JOHN
1,ELVIS
1,MICHAEL
1,KELVIN
TABLE2 (ID_OWNER, NAME)
1,KELVIN
My conditions are:
Only return the records from TABLE 1 if there isn't records from the same owner in TABLE 2
But if there are records in TABLE_2 must retrieve only the records from TABLE_2
I tried
SELECT
COALESCE(TB1.NAME,TB2.NAME)
FROM
TABLE_2 TB2
LEFT JOIN
TABLE_1 TB1 ON TB1.OWNER_ID = TB2.OWNER_ID
AND NOT EXISTS (SELECT 1
FROM TABLE_2 TB2_SUB
WHERE TB2_SUB.OWNER_ID = TB1.OWNER_ID)
WHERE
TB2.OWNER_ID = 1
but when TABLE_2 doesn't have records the query doesn't retrieve records.
You are overcomplicating your code:
SELECT *
FROM Table1 T1
WHERE NOT EXISTS(SELECT 1 FROM Table2
WHERE ID_OWNER = T1.ID_OWNER)
you could use the in operator:
SELECT *
FROM table1
WHERE id_owner NOT IN (SELECT id_owner FROM table2)

Select query in MySQL

Two tables
Table1
ID FileName
1 abc
2 abc
3 abc
4 xyz
Table2
ID Table1_ID isDeleted
1 1 1
2 2 1
3 3 0
4 4 0
I need to get the count of filename for the isDeleted=1 by passing any ID of table1, i.e for all the values(1,2,3) of ID, i need the count as 2
I tried with the following query
SELECT COUNT(t1.FileName) FROM Table1 t1
LEFT OUTER JOIN Table1 t11 ON t1.FileName=t11.FileName
INNER JOIN table2 t2 ON t2.Table1_ID =t1.ID AND t2.isDeleted=1
WHERE t1.ID=X;
X-1,2,3
This always returns 3.
Edit: I need to get the count of the filename from the first table by passing the ID from the first table. The count should be based on the isdeleted column in second table. The tables are related by the column ID (table1) and Table1_ID (table2)
Give this a shot:
select SUM(isDeleted)
from Table2
where Table1_ID in (
select ID from Table1
where FileName = (select FileName
from Table1
where ID = 1)
)
Edit: to get file count:
select count(*)
from Table1 a
join Table2 b on a.ID = b.Table1_ID and b.isDeleted = 1
where a.FileName = (select FileName
from Table1
where ID = 1)
This works for me:
declare #id int
set #id = 1 /*Or 2 or 3 or 4, etc.*/
select sum(isdeleted)
from table2
where table1_id in
(select id
from table1
where filename = (select filename
from table1
where id = #id))
Edit: I can't see how this is different from Fosco's answer.
SELECT COUNT(t1.FileName) FROM Table1 t1
INNER JOIN table2 t2 ON t2.Table1_ID =t1.ID AND t2.isDeleted=1
WHERE t1.ID=X;

query with join of 3 tables

I want a single query to produce the following results..
To result in records that are in table1 and in table2 and were not in table3.
There are more than 10,000 records in each table..so i am looking for an efficient one. In all the table Cono is the primary key..
In detail with tables.
TABLE 1:-
Cono
th-123
th-124
th-125
TABLE 2:-
Cono
th-234
th-245
th-256
TABLE 3:-
Cono
th-124
th-125
th-256
Now i want to have the following records
Result TABLE:-
Cono
th-123
th-234
th-245
Try this
WITH Table1 AS
(
SELECT 'th-123' CONO UNION
SELECT 'th-124' UNION
SELECT 'th-125'
)
,
Table2 AS
(
SELECT 'th-234' CONO UNION
SELECT 'th-245' UNION
SELECT 'th-256'
)
,
Table3 AS
(
SELECT 'th-124' CONO UNION
SELECT 'th-125' UNION
SELECT 'th-256'
)
SELECT CONO
FROM Table1
WHERE NOT EXISTS
(
SELECT 1
FROM Table3
WHERE TABLE1.CONO = TABLE3.CONO
)
UNION ALL
SELECT CONO
FROM Table2
WHERE NOT EXISTS
(
SELECT 1
FROM Table3
WHERE TABLE2.CONO = TABLE3.CONO
)
try this:
select t.cono from Table1 t WHERE NOT EXISTS (SELECT 1
FROM Table3 x WHERE x.cono=t.cono)
UNION
select t.cono from Table2 t WHERE NOT EXISTS (SELECT 1
FROM Table3 x WHERE x.cono=t.cono)
(SELECT t1.Cono FROM table1 t1
LEFT JOIN table3 t3
ON t3.Cono = t1.Cono
WHERE t3.Cono IS NULL)
UNION ALL
(SELECT t2.Cono FROM table2 t2
LEFT JOIN table3 t3
ON t3.Cono = t2.Cono
WHERE t3.Cono IS NULL)
Kind of vague tables and names, but here's what you can do if you REALLY wanna do it in one query:
SELECT Cono
FROM Table3
WHERE NOT EXISTS ( SELECT Cono
FROM TABLE1 as T
WHERE EXISTS ( SELECT *
FROM TABLE2
WHERE T.Cono = TABLE2.Cono));
This should select the values in table 3 that do not exist in the query that was created in parenthesis, which is a table made up of rows that are in tables 1 and 2.
Unfortunately, nesting and efficiency normally don't go hand-in-hand...
this one worked for me... and process fast:
select X.FID, c.id as CID
from
(
select a.id as FID from tbl1 a
union
select b.id as FID from tbl2 b
) as X
left outer join tbl3 c on FID = c.id
where
c.id is null
;
Try this (not tested):
; WITH all_data AS (
SELECT * FROM table1
UNION ALL
SELECT * FROM table2
)
SELECT *
FROM all_data ad
WHERE NOT EXISTS (
SELECT *
FROM table3 t3
WHERE ad.Cono = t3.Cono);

Changing IN to EXISTS in SQL

I have the following query:
select A,
B
from table1
where A in (select c
from table 2
)
But, now I need to change this query and use exists instead of in, and it should give the same results.
My tables look like the following:
table1 table2
A B c
------ -----
1 x 1
2 y 3
3 z 4
4 w 7
5 a
1 b
How do I use the exists function?
You need to match the two columns that will be used in the exists together:
select
t1.a, t1.b
from
table1 t1
where
exists (select 1 from table2 t2 where t2.c = t1.a)
The reason why you have to do that, is because exists performs a semi-join on the table, and therefore, needs to have a join condition.
Changing the expression:
FROM Table1 WHERE a IN( SELECT c FROM Table2 )
To an EXISTS is a simple matter of:
Add a WHERE on the end of the internal SELECT
FROM Table1 WHERE a IN( SELECT c FROM Table2 WHERE )
Move the external match column (a) into the internal SELECT's WHERE clause
FROM Table1 WHERE IN( SELECT c FROM Table2 WHERE a )
Move the internal match column (c) to the WHERE clause, leaving a column placeholder (a constant or *):
FROM Table1 WHERE IN( SELECT * FROM Table2 WHERE a = c )
Change the IN to EXISTS:
FROM Table1 WHERE EXISTS( SELECT * FROM Table2 WHERE a = c )
To be safe add the table name onto the external column:
FROM Table1 WHERE EXISTS( SELECT * FROM Table2 WHERE Table1.a = c )
This will do it via direct inner join.
select
t1.a, t1.b
from
table1 as t1
inner join table2 as t2 on t1.a=t2.c