|
|
Question : Finding multiple matches in join and also having 'grandchild' records in t-SQL
|
|
|
|
consider these 3 tables:
create table tblFirstTable ( FirstTablePK int not null, FirstTableKeyA VARCHAR(2 ) not null, FirstTableKeyB VARCHAR(6 ) not null, FirstTableAltKeyA VARCHAR(2 ) not null, FirstTableAltKeyB VARCHAR(6 ) not null, FirstTableAltKeyC VARCHAR(1 ) not null, FirstTableAltKeyX VARCHAR(2 ) not null, FirstTableAltKeyY VARCHAR(6 ) not null, FirstTableAltKeyZ VARCHAR(1 ) not null, )
create table tblSecondTable ( SecondTablePK int not null, SecondTableKeyA VARCHAR(2) not null, SecondTableKeyB VARCHAR(6) not null, SecondTableAltKeyX VARCHAR(2) not null, SecondTableAltKeyY VARCHAR(6) not null, SecondTableAltKeyZ VARCHAR(1) not null, Update_When DATETIME not null, Update_By VARCHAR(50) not null, )
create table tblThirdTable ( ThirdTablePK int not null, SecondTableFK int not null, AgentName VARCHAR(20 ) not null )
The join between tblFirstTable and tblSecondTable is on FirstTableKeyA = SecondTableKeyA AND FirstTableKeyB =SecondTableKeyB
For everyone of these joins, for each corresponding values of {FirstTableAltKeyX,FirstTableAltKeyY,FirstTableAltKeyZ} there may be 1 or more values in {SecondTableAltKeyX,SecondTableAltKeyY,SecondTableAltKeyZ}. This is the key condition.
I would like to select only records from tblFirsttable when the above key condition is satisfied and also if there are child record for tblSecondTable in tblThirdTable.
Example: tblFirstTable 1,'AA','BBBBBB','CC','DDDDDD','E','FF','GGGGGG','H' 2,'@@','######','$$','%%%%%%','^','&&','******','(' 3,'QQ','WWWWWW','EE','RRRRRR','T','YY','UUUUUU','I'
tblSecondTable 10,'AA','BBBBBB','II','JJJJJJ','K',datetime,John 11,'AA','BBBBBB','LL','MMMMMM','N',datetime,Mary 12,'AA','BBBBBB','OO','PPPPPP','Q',datetime,Joe 13,'@@','######','))','------','=',datetime,Jim 14,'@@','######','~~','!!!!!!',';',datetime,Jack 15,'QQ','WWWWWW','AA','SSSSSS','D'
tblThirdTable 20,11,'Miriam Racques' 21,12,'Roger Portes' 22,15,'Mike Penguert'
*For 'AA','BBBBBB' in tblFirstTable, we have records in tblSecondTable also, 3 of them. So we have multiple matches. This is criteria #1. And at least one of them has a child record in tblThirdTable. Hence both conditions satisfy, and we would like to bring the record in tblFirstTable in the query.
*For '@@','######' in tblFirstTable, we have records in tblSecondTable also, 2 of them.So we have multiple matches. This is criteria #1. But none of them have child records in tblThirdTable; because second criteria fails, we do not have to bring the row from tblFirstTable.
*For 'QQ','WWWWWW' in tblFirstTable, we have only one match in tblSecondTable (no multiple matches). Even though this has a child record (second criteria is satisfied), because the first criteria is not satisfied, we will not bring the row from tblFirstTable in the query.
how would you build the result desired in t-SQL code?.
thank you
|
|
|
|
Answer : Finding multiple matches in join and also having 'grandchild' records in t-SQL
|
|
Well, can be a few strategies as you can see from above...
The underlying relationships are resolved using a base of (if we needed all details) :
select T1.*, T2.*, T3.* from tblFirstTable T1 inner join tblSecondTable T2 on T1.FirstTableKeyA = T2.SecondTableKeyA AND T1.FirstTableKeyB =T2.SecondTableKeyB inner join tblThirdTable T3 on T2.SecondTablePK = T3.SecondTableFK
-- Considering there are PK's and FK's we assume appropriate indexing on those. -- So, reasonable to assume indexing on the TableKeyA and TableKeyB columns in their respective tables as well. -- Which means that we can be reasonably happy using joins. -- But we only really need counters... Not details...
select FirstTablePK as FPK, count(secondTablePK) as T2_count, count(thirdTablePK) as T3_count from tblFirstTable T1 inner join tblSecondTable T2 on T1.FirstTableKeyA = T2.SecondTableKeyA AND T1.FirstTableKeyB =T2.SecondTableKeyB inner join tblThirdTable T3 on T2.SecondTablePK = T3.SecondTableFK group by FirstTablePK having count(secondTablePK) > 1
-- Note, we dont have to count T3_count really, because the inner join will resolve the existance of at least 1 entry in tblThirdTable -- and really, we dont have to select T2_count because the Having clause does that count for us -- But we do need details, so, have to get back the tblFirstTable data.
select * from (select FirstTablePK as FPK from tblFirstTable T1 inner join tblSecondTable T2 on T1.FirstTableKeyA = T2.SecondTableKeyA AND T1.FirstTableKeyB =T2.SecondTableKeyB inner join tblThirdTable T3 on T2.SecondTablePK = T3.SecondTableFK group by FirstTablePK having count(secondTablePK) > 1) s inner join tblFirstTable on FPK = FirstTablePK
-- now, we have a subquery for our counter and select back the tblFirstTable -- so, really we can split out elements of that subquery so we only refer to tables once if possible -- and because it is a simple counter, we can actually have that part as the subquery only.
select * from tblFirstTable T1 Where 1 < (select count(secondTablePK) from tblSecondTable T2 inner join tblThirdTable T3 on T2.SecondTablePK = T3.SecondTableFK where T1.FirstTableKeyA = T2.SecondTableKeyA AND T1.FirstTableKeyB =T2.SecondTableKeyB)
-- there might be additional ways to explore, but think that does give the best performance, and the deliberations / steps used to get to that point :)
|
|
|
|