Joining with max date from table - sql

SELECT COL1,
COL2,
COL3
FROM TABLE1,
TABLE2,
TABLE3,
TABLE4
WHERE TABLE1.KEY1 = TABLE2.KEY1
AND TABLE2.KEY = TABLE3.KEY
AND TABLE2.FILTER = 'Y'
AND TABLE3.FILTER = 'Y'
AND TABLE2.KEY = TABLE3.KEY
AND TABLE3.KEY = TABLE4.KEY
I have a similar query and I need to do modification, in a table 3 there is a date column and I need to pick highest day value row for joining. Lets say there are 4 rows from table number 3 which are getting satisfied for join, I need to pick highest date row out of those 4 for joining purpose and then show the result.
Hope question is clear. Database oracle 10g

Try something like this query.
SELECT
COL1,
COL2,
COL3,
T33.*
FROM TABLE1
JOIN TABLE2 ON TABLE1.KEY1 = TABLE2.KEY1
JOIN TABLE4 ON TABLE2.KEY = TABLE4.KEY
JOIN
(
SELECT MAX(T.Day) as DT, T.KEY
FROM TABLE3 T
WHERE T.FILTER = 'Y'
GROUP BY T.KEY
) T3 on TABLE4.KEY = T3.KEY
JOIN TABLE3 T33 ON T3.KEY = T33.KEY AND T3.DT = T33.Day
WHERE
TABLE2.FILTER = 'Y'
The main idea is that instead of
joining to TABLE3 you do this:
SELECT MAX(T.Day) as DT, T.KEY
FROM TABLE3 T
WHERE T.FILTER = 'Y'
GROUP BY T.KEY
give that table/recordset a name and join to it instead.
Then you can join again to the original TABLE3 (see T33)
to pull all the other needed columns from TABLE3 which are
not present in T3.
You can work out the other details, I think.

To minimally modify your current query, you can add a condition in your WHERE clause
AND TABLE3.DATE = (SELECT MAX(DATE) FROM TABLE3 WHERE TABLE3.FILTER = 'Y')
Although in the future I recommend using explicit JOINS.
SELECT COL1,
COL2,
COL3
FROM TABLE1
INNER JOIN TABLE2 ON TABLE1.KEY1 = TABLE2.KEY1
INNER JOIN TABLE3 ON TABLE2.KEY = TABLE3.KEY
INNER JOIN TABLE4 ON TABLE3.KEY = TABLE4.KEY
WHERE
TABLE2.FILTER = 'Y'
AND TABLE3.FILTER = 'Y'
AND TABLE3.DATE = (SELECT MAX(DATE) FROM TABLE3 WHERE TABLE3.FILTER = 'Y')

Related

Left outer join involving three tables

From the 3 tables below I need to find 'John', who has a bike but not a car.
I'm trying to use this syntax
Select <> from TableA A left join TableB B on A.Key = B.Key where B.Key IS null
so in practise I create a left join from the two tables but i'm bit confused how the where B.Key IS null fits in my query.
select t1.name from
(table1 t1 join table3 on table3.table1id = t1.id join table2 t2 on table3.table2id = t2.id)
left join
(table1 t11 join table3 on table3.table1id = t11.id join table2 t22 on table3.table2id = t22.id)
on t1.name = t11.name where t2.name = 'Bike' and t22.name = 'Car';
Table1
ID
NAME
1
John
2
Nick
Table2
ID
NAME
1
Bike
2
Car
Table3
table1ID
table2ID
1
1
2
1
2
2
If you want your query to run at all cost you can go for something monstrous like this:
select name from table1
left join (select table1Id, table2.id as CarId from table3 join table2 on table2.id = table3.table2Id where table2.name = 'Car') c on id=c.table1Id
left join (select table1Id, table2.id as BikeId from table3 join table2 on table2.id = table3.table2Id where table2.name = 'Bike') b on id=b.table1Id
where CarId is null and BikeId is not null
https://dbfiddle.uk/pbftUJQL
But at the end it is a rough equivalent of straightforward
select name from table1
where not exists (select * from table3 join table2 on table2.id = table3.table2Id where table1.id=table3.table1Id and table2.name = 'Car')
and exists (select * from table3 join table2 on table2.id = table3.table2Id where table1.id=table3.table1Id and table2.name = 'Bike')
You must analyze query plans to choose variant that offer better performance. It may be this one:
select table1.name from table1 join table3 on table1.id=table3.table1Id join table2 on table2.id = table3.table2Id
where table2.name = 'Bike'
and not exists (select * from table3 t3 join table2 t2 on t2.id = t3.table2Id where table1.id=t3.table1Id and t2.name = 'Car')
From the 3 tables below I need to find John who has a bike but not a
car.
I would rather use this approach, it allows you to include additional criteria (e.g. has a bike and a truck but not a car) by modifying the having clause instead of adding additional joins:
select table1.id, table1.name
from table3
join table1 on table3.table1id = table1.id
join table2 on table3.table2id = table2.id
group by table1.id, table1.name
having count(case when table2.name = 'bike' then 1 end) > 0
and count(case when table2.name = 'car' then 1 end) = 0
PS: your original query could be written like this (it was missing aliases and where clause):
select *
from table1
left join (
table3 as table3_bike join
table2 as table2_bike on table3_bike.table2id = table2_bike.id
) on table3_bike.table1id = table1.id and
table2_bike.name = 'bike'
left join (
table3 as table3_car join
table2 as table2_car on table3_car.table2id = table2_car.id
) on table3_car.table1id = table1.id and
table2_car.name = 'car'
where table2_bike.id is not null
and table2_car.id is null
This query has the potential to grow exponentially e.g. if John has two bikes and two cars it'll return 2 x 2 = 4 rows for John. Relational division using exists or having is recommended.

SQL how to return '0' if no row is found

This is my sql:
select
a.column1,
b.column2
from table1 a inner join table2 b
on a.column8 = b.column9
where b.column5 = '2018'
and b.column6 = 'G1';
Problem: a.column1/table1 holds 250000 rows, and b.column2/table2 holds only 153000 rows.
How can this sql be changed to reply 250000 rows, and print '0' in b.column2/table2 when row is not found?
You want a left join:
select t1.column1, coalesce(t2.column2, 0) column2
from table1 t1
left join table2 t2
on t2.column9 = t2.column1
and t1.column5 = '2018'
and t1.column6 = 'G1';
This selects all rows from table1, even if there is no match in table2 - in which case output column t2.column2 will be null, which we we turn to '0' with coalesce().
PS: if t2.column2 is not a number but a string, then use coalesce(t2.column2, '0') instead (note the single quotes).
select
a.column1,
COALESCE ( b.column2, 0)
from table1 a LEFT join table2 b
on a.column8 = b.column9
where b.column5 = '2018'
and b.column6 = 'G1';
You need to use LEFT JOIN
coalesce will replace NULL values with 0
Use LEFT JOIN :
SELECT T1.COL1, COALESCE(T2.COL2, 0)
FROM T1 LEFT JOIN
T2
ON T1.COL8 = T2.COL9 AND T2.COL5 = 2018 AND T2.COL6 = 'G1'

How do I look for non-matching values across 3 SQL tables?

I'm looking to do what I believe is a double-nested check across three tables, but have no idea how to do so.
I have Table1, Table2, and Table3.
All are tied by an ID and a "Longform" and "Shortform" in Table1:
I'm trying to find:
Entries whose IDs appear in Table2 that have the same Longform as those in Table3, but don't share the same Shortform.
This is about as far as I've gotten:
SELECT T2.Longform,T2.Shortform FROM(
SELECT Table1.Longform,Table1.Shortform,Table1.ID FROM OuterTable1.Table1
LEFT JOIN OuterTable2.Table2 on Table1.ID = Table2.ID)
WHERE Table2.ID IS NOT NULL) T2
;
I know I'm probably going to have to do another nested select, or a join, on Outertable3.Table3 but I'm not sure which... Or where...
Any help appreciated as always.
Try the following:
Select *
(
Select T1.*
from T2
inner join T1
on T1.ID = T2.ID
) as Tab
inner join
(
Select T1.*
from T3
inner join T1
on T1.ID = T3.ID
) as Tab2
on Tab.id = Tab2.id
and Tab.Longform = Tab2.Longform
and Tab.Shortform <> Tab2.Shortform
To get the longform join table1 to table2 or table3. Then use EXISTS to check in a subquery if the IDs of table1 are different but the longform is equal.
SELECT *
FROM table2 t21
INNER JOIN table1 t11
ON t11.id = t21.id
WHERE EXISTS (SELECT *
FROM table3 t32
INNER JOIN table1 t12
ON t12.id = t32.id
WHERE t12.id <> t11.id
AND t12.longform = t11.longform);
Assuming ID is unique in all three tables
Select t2.id,t2.shortform, t1.shortform AS shortformTab1, t2.longform
FROM table2 t2
JOIN table3 t3
ON t2.id = t3.id AND t2.longform = t3.longform
JOIN table1 t1
ON t2.id = t1.id AND t2.shortform != t1.shortform

SQL LEFT JOIN with WHERE class

there are two tables TABLE1 and TABLE2 in TABLE1 there are records which does not exist in TABLE2 with left join below i wanted to query all records which are in TABLE1 if the record does not exist in table2 however.
Note: about WHERE class in my code that is required this is because, there can be several records in the name of 'IN PROGRESS' in TABLE2 with one record in the name of 'GRADUATED' i wanted to distinct records based on table 1 ID that if there is any record in the name of 'GRADUATE' it should show only that else it should show inprogress.
SELECT DISTINCT
TABLE1.ID,
TABLE2.TRAINING_STATUS_CHECK
FROM TABLE1
LEFT JOIN TABLE2
ON TABLE1.ID = TABLE2.FK_ID_CLASS
WHERE NOT EXISTS
(
SELECT DISTINCT
TABLE1.ID,
TABLE2.TRAINING_STATUS_CHECK
FROM TABLE1
LEFT JOIN TABLE2
ON TABLE1.ID = TABLE2.FK_ID_CLASS
WHERE TABLE2.TRAINING_STATUS_CHECK = 'GRADUATED')
OR TABLE2.TRAINING_STATUS_CHECK = 'GRADUATED'
I see some odds with your query:
exists part are not related with you main query. I think you need some relation
distinct in part not exists are not needed
You filter columns with the same conditions as filter main row set
As I understand you want to get all rows from table1 with state 'GRADUATED' int table2 and any row from table1 where rows in table2 are not exists or state not equal 'GRADUATED'
SELECT DISTINCT
t1.ID,
t2.TRAINING_STATUS_CHECK
FROM TABLE1 t1
LEFT JOIN TABLE2 t2 ON t1.ID = t2.FK_ID_CLASS
WHERE NOT EXISTS
(
SELECT NULL /*its not nesessary what you need*/
FROM TABLE1 sub_t1
JOIN TABLE2 sub_t2 ON sub_t1.ID = sub_t2.FK_ID_CLASS /* left join replaced to inner */
WHERE sub_t2.TRAINING_STATUS_CHECK = 'GRADUATED'
AND sub_t1.ID = t1.ID /*relation with outer query*/
)
OR t2.TRAINING_STATUS_CHECK = 'GRADUATED'
where the relatonship between tables does not exist - but only if the comparison involves rows in table that are not 'graduated' (I think)
SELECT DISTINCT
TABLE1.ID,
TABLE2.TRAINING_STATUS_CHECK
FROM TABLE1
LEFT JOIN TABLE2 ON TABLE1.ID = TABLE2.FK_ID_CLASS
AND TABLE2.TRAINING_STATUS_CHECK <> 'GRADUATED'
WHERE TABLE2.FK_ID_CLASS IS NULL
Not sure about your question but if you want all the records from table 1 who are not in table 2, you just have to do this :
SELECT TABLE1.ID
FROM TABLE1
LEFT JOIN TABLE2 ON TABLE1.ID = TABLE2.FK_ID_CLASS
WHERE TABLE2.FK_ID_CLASS IS NULL
Try this:
SELECT DISTINCT TABLE1.ID, TABLE2.TRAINING_STATUS_CHECK
FROM TABLE1
LEFT JOIN TABLE2
ON TABLE1.ID = TABLE2.FK_ID_CLASS
AND (NOT EXISTS (SELECT 1
FROM TABLE2 t
WHERE TABLE1.ID = t.FK_ID_CLASS
AND t.TRAINING_STATUS_CHECK = 'GRADUATED')
OR TABLE2.TRAINING_STATUS_CHECK = 'GRADUATED')
For the record, conditions on the right table of a LEFT JOIN need to be placed inside the ON() clause or the join will transfer into an INNER JOIN due to NULL comparison.
It seems to me you have three distinct cases that can be "ORed together" using UNION; personally I find keeping all three separated like this makes things much easier to read and understand:
--- ID with GRADUATED exists in TABLE2
( SELECT ID, 'GRADUATED' AS TRAINING_STATUS_CHECK
FROM TABLE1
INTERSECT
SELECT FK_ID_CLASS, 'GRADUATED'
FROM TABLE2
WHERE TRAINING_STATUS_CHECK = 'GRADUATED' )
UNION
--- ID without GRADUATED exists in TABLE2
( SELECT ID, 'IN PROGRESS'
FROM TABLE1
MINUS
SELECT FK_ID_CLASS, 'IN PROGRESS'
FROM TABLE2
WHERE TRAINING_STATUS_CHECK = 'GRADUATED' )
UNION
--- ID does not exist in TABLE2
( SELECT ID, '{{NONE}}'
FROM TABLE1
WHERE ID NOT IN ( SELECT FK_ID_CLASS FROM TABLE2 ) );

Help with sql join

I have two tables:
Table 1:
ID, PersonCode, Name,
Table 2:
ID, Table1ID, Location, ServiceDate
I've got a query joining table 1 to table 2 on table1.ID = table2.Table1ID where PersonCode = 'XYZ'
What I want to do is return Table1.PersonCode,Table1.Name, Table2.Location, Table2.ServiceDate, I don't want all rows, In table 2 I'm only interested in the row with the most recent ServiceDate for each location. How would I go about doing this?
Something like this:
SELECT
Table1.PersonCode, Table1.Name, Table2.Location, MAX(Table2.ServiceDate)
FROM
Table1
INNER JOIN Table2 on Table1.ID = Table2.Table1ID
WHERE
TABLE1.PersonCode = 'XYZ'
GROUP BY
Table1.PersonCode,Table1.Name, Table2.Location
Use MAX(ServiceDate)
Try:
select Table1.PersonCode,Table1.Name, Table2.Location, Table2.ServiceDate
from Table1
join Table2 on table1.ID = table2.Table1ID
where table1.PersonCode = 'XYZ'
and table2.ServiceDate = (select max(t2.ServiceDate)
from table2 t2
where t2.table1ID = table2.table1ID
and t2.location = table2.location
);
I would use an INNER JOIN and select the first record, having ordered the records in reverse chronological order based on Table2.ServiceDate.
SELECT TOP 1
Table1.PersonCode, Table1.Name, Table2.Location, Table2.ServiceDate
FROM
Table1
INNER JOIN Table2 on Table1.ID = Table2.Table1ID
WHERE
TABLE1.PersonCode = 'XYZ'
ORDER BY Table2.ServiceDate DESC
GROUP BY
Table1.PersonCode,Table1.Name, Table2.Location