SQL Server - Join across several tables - sql-server

Below are the relevant tables info:
tgenie
Guid | genietypeguid | ...
and :
tgenieType
guid | genietype | ...
I made this query to select all possible entries:
select
tsearch.description,
tcompany.CompanyName,
tsearch.CompanyGUID,
tgenie.GenieNotes,
tGenieType.GenieType
from
tcompany, tsearch, tGenieType
left outer join
tGenie on tgenie.GenieTypeGUID = tGenieType.GUID
As the result I have this output:
description | CompanyName | CompanyGUID | GenieNotes | GenieType
VP Buiness AP Dev | Test | 5920B842-8216-45AA-A2AF-EA69740959FC | Test2 | Add'l Candidate Info
VP Buiness AP Dev | Test | 5920B842-8216-45AA-A2AF-EA69740959FC | Test3 | Add'l Candidate Info
VP Buiness AP Dev | Test | 5920B842-8216-45AA-A2AF-EA69740959FC | Test5 | Add'l Candidate Info
.
.
.
However, it does not work as supposed.
GenieType is set as "Add'l Candidate Info" for all the entries. I had ran the query for a long time and it seem to be the same for all the rows ... which does not seem right.
Any body has an idea why my join does not work?
Thanks in advance!
Update 1
I ended up with this query
It took 9 mins and has 1478028 rows...
select tsearch.Description,
tcompany.CompanyName,
tcompany.GUID as CompanyGuid,
tcompanylocation.LocationName,
tsearchtype.SearchType,
tsearchresult.searchresult,
tpeople.GUID as PersonPlacedGuid,
tpeople.LastName As PersonPlacedLName,
tpeople.Firstname As PersonPlacedFName,
tpeople.address1,
tpeople.address2,
tpeople.city,
tpeople.zipcode,
tpeople.city2,
tpeople.zipcode2,
tpeople.emailaddress,
tpeople.website,
tpeople.homephone,
tpeople.OtherPhoneDescription1,
tpeople.otherphone1,
tpeople.otherphonedescription3,
tpeople.otherphone3,
tpeople.resumefile,
tpeople.resumeocr,
tpeople.timeentered,
tPeopleEducation.education,
tPeopleEducation.GradYear,
tsearch.SearchNotes,
( select tpeople.Firstname from tpeople where tpeople.guid=tSearch.RepresentativeGUID) as repfirstname,
( select tpeople.Lastname from tpeople where tpeople.guid=tSearch.RepresentativeGUID) as replastname,
tsearch.RepresentativeGUID as RepGuid,
tposition.Position as backgroundposition,
tdepartment.Department as backgrounddepartment,
( select tpeople.Lastname from tpeople where tpeople.guid=tSearch.ReferredByGUID) as referredbylastname,
( select tpeople.FirstName from tpeople where tpeople.guid=tSearch.ReferredByGUID) as referredbylastname,
tsearch.ReferredByGUID as PersonwhorefferedGuid,
( select tcompany.CompanyName from tCompany where tCompany.guid=tSearch.PlacedFromGUID) as placedfrom,
tinstantstatustype.InstantStatus,
tWorkbench.WorkbenchName,
( select tpeople.Lastname from tpeople where tpeople.guid=tInstantStatus.PeopleGUID) as Candlastname,
( select tpeople.FirstName from tpeople where tpeople.guid=tInstantStatus.PeopleGUID) as candFirstname,
tInstantStatus.ForClientNotes,
tinstantstatus.InstantStatusNotes as InstanttatusNotesSummary,
tGenie.GenieNotes,
tGenieType.GenieType,
tgenielabel.GenieLabel
from tcompany
inner join tsearch on tCompany.GUID = tSearch.CompanyGUID
left join tcompanylocation on tcompanylocation.guid= tcompany.LocationGUID
left join tSearchType on tsearchtype.GUID = tSearch.SearchTypeGUID
left join tSearchResult on tSearchResult.GUID = tsearch.SearchResultGUID
left join tPeople on tPeople.GUID = tsearch.PlacedGUID
left join tPosition on tPosition.GUID = tsearch.PositionGUID
left join tDepartment on tdepartment.GUID = tsearch.DepartmentGUID
left join tInstantStatus on tInstantStatus.SearchGUID = tSearch.guid
left join tInstantStatusType on tInstantStatusType.GUID = tInstantStatus.InstantStatusGUID
left join tWorkbench on tWorkbench.SearchGUID=tsearch.GUID
left join tSearchCluendex on tSearchCluendex.CPSGUID=tsearch.GUID
left join tpeopleEducation on tpeople.GUID = tpeopleEducation.PeopleGUID
left join tBusDev on tsearch.GUID = tbusdev.SearchGUID
left join tGenie on tbusdev.GUID = tgenie.BusDevGUID
left join tGenieLink on tGenie.GUID = tgenielink.GenieGUID
left join tGenieLabel on tgenielink.GenieLabelGUID = tGenieLabel.GUID
left join tGenieType on tgenie.GenieTypeGUID=tGenieType.GUID
Weird is that in the system 57 GenieType are defined and only 4 were found. Also with GenieLabel, in the system 16 are defined and only 6 were found.
I am beginner in SQL/TSQL and this query seems quite big .... does it look OK? Or it is hard to tell without more info about DB structure ...
HMMM.... there are different answers suggested, but this above seem to work.
Why should I use:
inner join
inner join
left outer
vs
inner join
left join
left join
vs
join
join
left join
????
Update 2:
Thanks #Daniel for your help. I attached the diagram as you suggested.
What I want to get can be seen in my query from Update 1
Hope some good soul can help.

Your query is performing a CROSS JOIN between tcompany, tsearch and tGenieType, and then tries to join on a corresponding record in the tGenie table. This means your query will return a record for every combination of tcompany, tsearch and tGenieType possible, regardless of any relations between them, and will then try to link the results to tGenie records using your condition, potentially multiplying the results once more.
When you say that you want "all possible entries", what exactly do you want to achieve?
Typically, as well as from your queried columns, you'd want to perform a INNER JOIN or a LEFT JOIN rather than a CROSS JOIN. For example :
SELECT
tSearch.Description,
tCompany.CompanyName,
tSearch.CompanyGUID,
tGenie.GenieNotes,
tGenieType.GenieType
FROM
tCompany
INNER JOIN tSearch ON tCompany.GUID = tSearch.CompanyGUID
LEFT JOIN tGenie ON tSearch.GUID = tGenie.SearchGUID
LEFT JOIN tGenieType ON tGenieType.GUID = tGenie.GenieTypeGUID
This would pull every tSearch from every tCompany, matching them according to their foreign keys, and then try to match with the corresponding tGenie records based on an hypothetical GUID column before doing the same with the tGenieType.

I suggest trying maybe this.
SELECT tsearch.description
,tcompany.CompanyName
,tsearch.CompanyGUID
,tgenie.GenieNotes
,tGenieType.GenieType
FROM tcompany
JOIN tsearch
ON tcompany.SomeID = tsearch.SomeID
JOIN tGenieType
ON tcompany.SomexID = tGenieType.SomexID
LEFT JOIN tGenie
ON tgenie.GenieTypeGUID = tGenieType.GUID
You accidentaly stumbled upon cross join. Also, connecting your tables will have to go over keys, so make sure you identify them correctly. A good visual reference on what's going on with joins is on codinghorror blog.

You are not joining the other tables in FROM (and this syntax is not longer supported in new versions of Sql Server)
Should be like this:
select tsearch.description
,tcompany.CompanyName
,tsearch.CompanyGUID
,tgenie.GenieNotes
,tGenieType.GenieType
from tcompany
inner join tsearch on tcompany.XXX = tsearch.XXX
inner join tGenieType on tcompany.YYY = tsearch.YYY
left outer join tGenie on tgenie.GenieTypeGUID=tGenieType.GUID

Related

Join 4 tables and sum quantity for 2 tables using id from one table

My tables:
Order is:
PurchaseOrderHead
PurchaseOrder
ReceivingNoteHead
ReceivingNote
I want the output like this
MaterialID, PO.Quantity, RN.Quantity so far
There can be multiple receiving notes for a given purchaseorderhead_id as every ReceivingNoteHead will have a PurchaseOrderHeadID.
My attempt:
select
PurchaseOrder.MaterialID,
sum(distinct PurchaseOrder.Quantity) as "Sum_Quantity",
sum(ReceivingNote.Quantity) as "ReceivingNote_Quantity",
PurchaseOrderHead.id
from
(((dbo.PurchaseOrder
inner join
dbo.PurchaseOrderHead on (PurchaseOrderHead.id = PurchaseOrder.PurchaseOrderHeadID))
left outer join
dbo.ReceivingNoteHead ReceivingNoteHead (ReceivingNoteHead.PurchaseOrderHeadID = PurchaseOrderHead.id))
left outer join
dbo.ReceivingNote on (ReceivingNote.ReceivingNoteHeadID = ReceivingNoteHead.id))
group by
PurchaseOrder.MaterialID,
PurchaseOrderHead.id
having
(PurchaseOrderHead.id = 1004)
But ReceivingNote Quantities are repeated when there's no ReceivingNote MaterialID that matches PurchaseOrder's MaterialID.
This also does not work when theres multiple same MaterialID in either PurchaseOrder or ReceivingNote
I would like to learn whether I need to break the ReceivingNote table into 2 tables because of PurchaseOrderHeadID? And I want to get rid of the sum distinct because it's not the way I want it to be.
Maybe by first aggregating the material purchases in a sub-query.
Then left join that to the materials on the receiving end.
Untested notepad scribble:
SELECT
poMat.MaterialID,
poMat.TotQuantity AS [PurchaseOrder_Quantity],
SUM(rn.Quantity) AS [ReceivingNote_Quantity],
poMat.PurchaseOrderHeadID
FROM
(
SELECT
po.PurchaseOrderHeadID,
po.MaterialID,
SUM(po.Quantity) AS TotQuantity
FROM dbo.PurchaseOrder po
-- Uncomment to filter on the PurchaseOrderHeadID
-- WHERE po.PurchaseOrderHeadID = 1004
GROUP BY
po.PurchaseOrderHeadID,
po.MaterialID
) poMat
LEFT JOIN dbo.ReceivingNoteHead rnH
ON rnH.PurchaseOrderHeadID = poMat.PurchaseOrderHeadID
LEFT JOIN dbo.ReceivingNote rn
ON rn.ReceivingNoteHeadID = rnH.id
AND rn.MaterialID = poMat.MaterialID
GROUP BY
poMat.PurchaseOrderHeadID,
poMat.MaterialID,
poMat.TotQuantity
ORDER BY
poMat.PurchaseOrderHeadID,
poMat.MaterialID;
This however, won't show received materials that don't have a matching purchased material.
You are getting duplicate because the table ReceivingNoteHead does not have the PurchaseOrder.ID in it. Add the column PurchaseOrderID in ReceivingNoteHead and you should be good to go
select
PurchaseOrder.MaterialID,
sum(PurchaseOrder.Quantity) as "Sum_Quantity",
sum(ReceivingNote.Quantity) as "ReceivingNote_Quantity",
PurchaseOrderHead.id
from
dbo.PurchaseOrder
inner join
dbo.PurchaseOrderHead on PurchaseOrderHead.id = PurchaseOrder.PurchaseOrderHeadID
left outer join
dbo.ReceivingNoteHead ReceivingNoteHead ReceivingNoteHead.PurchaseOrderHeadID = PurchaseOrderHead.id *and ReceivingNoteHead.PurchaseOrderID=PurchaseOrder.ID*
left outer join
dbo.ReceivingNote on ReceivingNote.ReceivingNoteHeadID = ReceivingNoteHead.id
group by
PurchaseOrder.MaterialID,
PurchaseOrderHead.id
having
PurchaseOrderHead.id = 1004

IS NULL being ignored

I am trying to run a query in T-SQL to pull back a data set based on a column being null.
This is a simplified version of the code:
SELECT
T1.Col1, T1.Col2,
T1.Col3, T1.Col4
FROM
table1 AS T1
INNER JOIN
table2 AS T2 ON T1.Col2 = T2.Col3
WHERE
T2.Col4 IS NULL
Problem is, the result includes rows where T2.Col4 are NULL and also not NULL, it's like the WHERE clause doesn't exist.
Any ideas would be greatly
UPDATE - full version of code:
SELECT
M.ref
,C.cname
,CL.clname
,C.ccity
,M.productLine
,M.code
,CL.date
,M.dept
,DPT.group
,TK2.tkname
,TK2.tkdept
FROM DB.dbo.manage AS M
OUTER JOIN DB.dbo.ClientManageRelationship AS CMR
ON CMR.RelatedEntityID = M.EntityID
OUTER JOIN DB.dbo.Client AS C
ON C.EntityID = CMR.EntityID
INNER JOIN DB.dbo.ManageCustomerRelationship AS MCR
ON MCR.EntityID = M.EntityID
INNER JOIN DB.dbo.Customer AS CL
ON CL.EntityID = MCR.RelatedID
INNER JOIN DB.dbo.timek AS TK
ON TK.tki = M.tkid
LEFT JOIN (SELECT Group = division, [Department] = newdesc, deptcode FROM DB.csrt.vw_rep_p_l_dept) AS DPT
ON tkdept = DPT.dept
LEFT JOIN (SELECT Name = TK2.tkfirst + ' ' + TK2.tklast, TK2.tki, TK2.dept, TK2.loc FROM DB.dbo.timek as TK2 WITH(NOLOCK)) AS TK2
ON TK2.tki = M.tkid
WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND TK.tkloc = 'loc1' OR TK.tkloc = 'loc2'
ORDER BY M.ref
My first answer would be because you're using INNER JOIN. This only returns matches between the 2 tables. TRY FULL OUTER JOIN which will return all values regardless of matches and will include NULLS.
If you were looking to return all rows regardless of matches including NULLS from only one of the tables then use RIGHT or LEFT JOIN.
Say i had 2 tables ('Person' and 'Figure'). Not every person may have entered a figure on any one day. But an example may be i want to return all people regardless of whether they entered a figure or not on a certain day.
My initial approach to this would be a LEFT join because i want to return of all the people(left table) regardless of there being any matches in the figure table(right table)
FROM Person P
LEFT JOIN Figure F
ON P.ID = F.ID
This would produce a result such as
Name Figure
Sam 20
Ben 30
Matt NULL
Simon NULL
Whereas,
An inner join would produce only matching values not including nulls
Name Figure
Sam 20
Ben 30
Left join works the same way as right join but in the opposite direction. This is most likely the problem you were facing. But i hope this helped
I think the problem is in the last part of the where condition.
You should use brackets.
`WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND (TK.tkloc = 'loc1' OR TK.tkloc = 'loc2')`
or
`WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND TK.tkloc IN ('loc1', 'loc2')`

INNER JOIN clause ignoring NULL values

I am looking to query some data that pertains to medications a patient has been prescribed that are in a certain category. But I also want to show patients that do not have any medications. My query so far:
SELECT
pd.fname,
pd.lname,
pp.drug_name,
pp.drug_strength
FROM
patient_data pd
FULL OUTER JOIN patient_prescr pp on pp.pid = pd.pid
FULL OUTER JOIN formulary f on pp.med_id = f.id
INNER JOIN formulary_categories fc on f.category = fc.id AND fc.id in (34,36,37,38,5)
WHERE
pd.lname = 'Test'
When applying the INNER JOIN to formulary_categories, I can correctly specify the category in which the drug I want to specify, but when I do this, it WILL NOT include patients that do not have any medications.
With the INNER JOIN joining the formulary_categories table, my results look like this:
-----------------------------------------------------------------------
fname | lname | drug_name | drug_strength
-----------------------------------------------------------------------
Cathy Test Clonazepam 0.5mg
Larry Test Librium 25mg
Jennifer Test Vistrail 25mg
-----------------------------------------------------------------------
If I change the INNER JOIN to a FULL OUTER JOIN, it simply ignores the category constraint, and pulls all categories.
However, the query will not include patients that do not have any medications prescribed. Id like my results to look something like:
-----------------------------------------------------------------------
fname | lname | drug_name | drug_strength
-----------------------------------------------------------------------
Cathy Test Clonazepam 0.5mg
Larry Test Librium 25mg
Joe Test NULL NULL
Jennifer Test Vistrail 25mg
Steve Test NULL NULL
-----------------------------------------------------------------------
You are actually looking for LEFT JOIN:
SELECT
pd.fname,
pd.lname,
pp.drug_name,
pp.drug_strength
FROM
patient_data pd
FULL OUTER JOIN patient_prescr pp on pp.pid = pd.pid
FULL OUTER JOIN formulary f on pp.med_id = f.id
LEFT JOIN formulary_categories fc on f.category = fc.id
AND fc.id in (34,36,37,38,5)
WHERE
pd.lname = 'Test'
A LEFT JOIN will not filter data if a correlation is not found between the values in the two tables (or result sets) and will display a NULL value for the columns which displays data from the table where a correlation was not found (just like in your expected output sample).
You can also take a look at the best article (in my opinion) for understanding all types of JOINs, here.
You simply need LEFT OUTER JOIN :
SELECT
pd.fname,
pd.lname,
pp.drug_name,
pp.drug_strength
FROM
patient_data pd
FULL OUTER JOIN patient_prescr pp on pp.pid = pd.pid
FULL OUTER JOIN formulary f on pp.med_id = f.id
LEFT OUTER JOIN formulary_categories fc on f.category = fc.id AND fc.id in (34,36,37,38,5)
WHERE
pd.lname = 'Test'

Inner Join and Left Join in same sql query

I'm trying to perform inner join and then left join in same sql query.
But the left join is not working. It is not showing the null values
I've two tables EVENT_INVITATIONS and USERINFO which has 2 records when joined.
so, the join query goes like this :
select * from [UandMePROD].[dbo].EVENT_INVITATIONS EI
join [UandMePROD].[dbo].USERINFO UI on EI.USER_ID = UI.USER_ID and EI.EVENT_ID=11033
It gives out 2 records.
So, I'm performing a left join with another table CLIENT_CONTACTS which has only 1 matching record in it.
So, actually it should show the null value to the unmatched record. but it is not showing the second record. It is showing only 1 record which is matched(join)
My failed sql query :
select * from [UandMePROD].[dbo].EVENT_INVITATIONS EI
join [UandMePROD].[dbo].USERINFO UI on EI.USER_ID = UI.USER_ID
left join CLIENT_CONTACTS CC on UI.MOBILENO=CC.MOBILE_NUMBER
where cc.CLIENT_ID=20111 and EI.EVENT_ID=11033
can you please tell me where I'm doing mistake?
I need the 2 records.
Since you are doing a left join, cc.CLIENT_ID is null for all the values which only exist in CLIENT_CONTACTS and your where clause Where cc.CLIENT_ID = 20111
converts your LEFT JOIN into INNER JOIN. Adding this filter in ON clause solves the issue.
select *
from [UandMePROD].[dbo].EVENT_INVITATIONS EI
inner join [UandMePROD].[dbo].USERINFO UI on EI.[USER_ID] = UI.[USER_ID]
left join CLIENT_CONTACTS CC on UI.MOBILENO = CC.MOBILE_NUMBER
and cc.CLIENT_ID = 20111
where EI.EVENT_ID=11033
You should not specify EI.EVENT_ID on WHERE clause. Those limit your results after the join. You should specify EI.EVENT_ID in an ON clause.
select * from [UandMePROD].[dbo].EVENT_INVITATIONS EI join [UandMePROD].[dbo].USERINFO UI on EI.USER_ID = UI.USER_ID AND (EI.EVENT_ID=11033 or EI.EVENT_ID is null) left join CLIENT_CONTACTS CC on UI.MOBILENO=CC.MOBILE_NUMBER where cc.CLIENT_ID=20111
Providing some suggestions,since it is not possible to say what is happening with out table data
Left join should show null values from output of first inner join eventhough there are no mobile number matches,so try removing where condition and see if you are getting any result

Query on 3 tables with two outer joins

I have a problem with running a T-SQL query to join 3 tables, dimStores, fctSales, dimDates.
I need to retain all rows from dimStores (list of selected stores) and dimDates (selection of dates) and matching details from fctSales. I can only join them via fctSales table that has keys for stores and dates.
I tried left outer join to get full list of selected Stores and then Right outer join to get all Dates but never was able to get both at the same time.
dimStores (StoreName)
fctSales (StoreName, DateKey)
dimDates (Date)
SELECT
st.StoreName
,sa.SaleItem
,dd.DateKey
From dimStores as st
Left outer join fctSales as sa on st.StoreName = sa.StoreName
right outer join dimDates as dd on dd.DateKey = sa.DateKey
WHERE dd.DateKey between 20150101 and 20150115
and sa.StoreName in ('Aka','Bink','Gil')
Please help
give it a try
with the left join with the fact you did in fact keep the Stores but with the right join on date, only the stores with data on that date would be considered
To keep all the stores on every possible date full outer join both to get all the combinations and only then join with the data.
SELECT
st.StoreName
,sa.SaleItem
,dd.DateKey
From dimStores as st
full outer join dimDates as dd on
1=1
Left outer join fctSales as sa on
st.StoreName = sa.StoreName and
dd.DateKey = sa.DateKey
WHERE
dd.DateKey between 20150101 and 20150115 and
sa.StoreName in ('Aka','Bink','Gil')

Resources