Need to join but on a secondary table - sql

I have this one view all_people_expanded_view that has all the data needed except 1.
The race of client is in race table. But the description is in race_info. I need to join on race on people_id, but really need then to join race on race_info on column race_info_id and then get description. I am stuck on how to make this connection.
select a.full_name, a.dob, a.gender, a.ethnicity, c.race_info_id
from all_people_expanded_view a inner join
race c
on a.people_id = c.people_id
this would be fine but it only has race_info_id and not the description which is in the race_info_id table.

Is this what you're looking for?
select
a.full_name,
a.dob,
a.gender,
a.ethnicity,
c.race_info_id,
ri.description
from
all_people_expanded_view a
inner join
race c
on a.people_id = c.people_id
left join --Maybe an inner join, depending on your data
race_info ri
on ri.race_info_id = c.race_info_id

select
a.full_name, a.dob, a.gender, a.ethnicity, c.race_info_id , ri.description
from
all_people_expanded_view a
inner join race c on a.people_id = c.people_id
inner join race_info ri on ri.race_info_id = c.race_info_id

Related

SQL: Multiple joins on multiple tables where some column values are not mandatory

I am trying to join multiple tables where the values in columns e.Email, e.Phone are voluntary. I would like to select all rows even if e.Email, e.Phone contain empty values.
Currently, I am only able to select rows where e.Email, e.Phone values are present.
SELECT a.ID_1
,b.Tier
,e.Email
,e.Phone
FROM CustomerActivity a
JOIN CustomerSummary b
ON a.ID_1 = b.ID_1
JOIN DimensionCustomer c
ON b.ID_1 = c.ID_1
JOIN LegacyCustomerMapping d
ON c.ID_2 = d.ID_2
JOIN LegacyCustomerContactData e
d.ID_3 = e.ID_3
Many thanks for any kind of advice!
I would recommend using left join instead of join in your query. That should get the results you are looking for.
Image from: https://www.w3schools.com/sql/sql_join.asp
This can be obtained by using a LEFT OUTER JOIN for the table containing the Email and Phone fields:
SELECT a.ID_1, b.Tier, e.Email ,e.Phone
FROM CustomerActivity a
JOIN CustomerSummary b ON a.ID_1 = b.ID_1
JOIN DimensionCustomer c ON b.ID_1 = c.ID_1
JOIN LegacyCustomerMapping d ON c.ID_2 = d.ID_2
LEFT OUTER JOIN LegacyCustomerContactData e d.ID_3 = e.ID_3
Using an OUTER JOIN avoids records not being returned when there are no related rows in the joined table. Note that OUTER is optional and might not be supported by all databases.

SQL many to many select people with multiple vacancies

I am working with sql server through SSMS right now. How can i choose all people with multiple(>2)vacancies?
I am trying something like that, but i dont understand how to make part with "more than 2 vacancies"?
SELECT dbo.applicants.FirstName, dbo.vacancy.Name
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id = dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id WHERE dbo.vacancy.Name='third vacancy'
SELECT dbo.applicants.FirstName, dbo.vacancy.Name
FROM dbo.applicants A INNER JOIN
dbo.VacancyApplicant V ON A.id = V.ApplicantId
WHERE EXIST(
SELECT 1
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id =
dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id
WHERE A.id=dbo.applicants.id
GROUP BY dbo.applicants.id,dbo.vacancy.id
HAVING COUNT(1)>2
)
Group By and Having are you basic answer. Below is a simple solution, might not be ideal, but can give you the idea.
I am finding target "applicants" ids in subquery, that uses GROUP BY and HAVING then outer query joins to that to output FirstName and LastName of applicant
SELECT dbo.applicants.FirstName, dbo.applicants.LastName FROM
dbo.applicants a INNER JOIN
(
SELECT dbo.applicants.id
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id = dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id AND dbo.vacancy.Name='third vacancy'
GROUP BY dbo.applications.id
HAVING COUNT(dbo.vacancy.id) > 2
) targetIds ON a.id = targetIds.id
"more than 2 vacancies"?
Your question only mentions vacancies but your query is filtering for a particular name. I assume you really want more than two of that name.
If I understand correctly, you want aggregation:
SELECT a.FirstName, a.Name
FROM dbo.applicants a INNER JOIN
dbo.VacancyApplicant va
ON a.id = va.ApplicantId INNER JOIN
dbo.vacancy v
ON va.VacancyId = v.id
WHERE v.Name = 'third vacancy'
GROUP BY a.FirstName, v.Name
HAVING COUNT(*) > 2;
Note the use of table aliases. They make the query easier to write and to read.
WITH TempCTE AS (
SELECT DISTINCT ap.FirstName
,vc.Name
,COUNT (va.VacancyId) OVER (PARTITION BY ap.id) AS NoOfVacancies
FROM dbo.applicants ap
JOIN dbo.VacancyApplicant va
ON ap.id = va.ApplicantId
JOIN dbo.vacancy vc
ON va.VacancyId = vc.id
)
SELECT FirstName,[Name], NoOfVacancies FROM TempCTE
WHERE NoOfVacancies > 2

How to create distinct count from queries with several tables

I am trying to create one single query that will give me a distinct count for both the ActivityID and the CommentID. My query in MS Access looks like this:
SELECT
tbl_Category.Category, Count(tbl_Activity.ActivityID) AS CountOfActivityID,
Count(tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;
I know the answer must somehow include SELECT DISTINCT but am not able to get it to work. Do I need to create multiple subqueries?
This is really painful in MS Access. I think the following does what you want to do:
SELECT ac.Category, ac.num_activities, aco.num_comments
FROM (SELECT ca.category, COUNT(*) as num_activities
FROM (SELECT DISTINCT c.Category, a.ActivityID
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as caa
GROUP BY ca.category
) as ca LEFT JOIN
(SELECT c.Category, COUNT(*) as num_comments
FROM (SELECT DISTINCT c.Category, co.CommentId
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as aco
GROUP BY c.Category
) as aco
ON aco.CommentId = ac.CommentId
Note that your LEFT JOINs are superfluous because the WHERE clause turns them into INNER JOINs. This adjusts the logic for that purpose. The filtering is also very tricky, because it uses both tables, requiring that both subqueries have both JOINs.
You can use DISTINCT:
SELECT
tbl_Category.Category, Count(DISTINCT tbl_Activity.ActivityID) AS CountOfActivityID,
Count(DISTINCT tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;

Can you have an INNER JOIN without the ON keyword?

While debugging into some Oracle code, I came across this query:
SELECT TPM_TASK.TASKID FROM TPM_GROUP
INNER JOIN TPM_USERGROUPS ON TPM_GROUP.GROUPID = TPM_USERGROUPS.GROUPID
INNER JOIN TPM_TASK
INNER JOIN TPM_GROUPTASKS ON TPM_TASK.TASKID = TPM_GROUPTASKS.TASKID
INNER JOIN TPM_PROJECTVERSION ON TPM_TASK.PROJECTID = TPM_PROJECTVERSION.PROJECTID AND TPM_TASK.VERSIONID = TPM_PROJECTVERSION.VERSIONID
INNER JOIN TPM_TASKSTAGE ON TPM_TASK.STAGEID = TPM_TASKSTAGE.STAGEID
INNER JOIN TPM_PROJECTSTAGE ON TPM_PROJECTVERSION.STAGEID = TPM_PROJECTSTAGE.STAGEID
ON TPM_GROUP.GROUPID = TPM_GROUPTASKS.GROUPID
I'm confused by the line:
INNER JOIN TPM_TASK
I haven't seen a JOIN without an ON clause before. Also confusing is the line:
ON TPM_GROUP.GROUPID = TPM_GROUPTASKS.GROUPID
This seems like a random ON clause without any matching JOIN. The query runs without any errors, and returns a bunch of data, so obvious the syntax is perfectly valid. Can someone shed some light on exactly what's going on here?
Small universe... I ran across a tool generating this syntax yesterday and was rather flummoxed.
Apparently,
FROM a
INNER JOIN b
INNER JOIN c ON (b.id = c.id)
ON (a.id = c.id)
is equivalent to a nested subquery
FROM a
INNER JOIN (SELECT <<list of columns>>
FROM b
INNER JOIN c ON (b.id=c.id)) c
ON (a.id = c.id)
I think that this is only a problem of ordering your query (since there are only INNER JOINs, the order of them is not really that important). I rearrenged your query and now it looks like this:
SELECT TPM_TASK.TASKID
FROM TPM_GROUP
INNER JOIN TPM_USERGROUPS
ON TPM_GROUP.GROUPID = TPM_USERGROUPS.GROUPID
INNER JOIN TPM_GROUPTASKS
ON TPM_GROUP.GROUPID = TPM_GROUPTASKS.GROUPID
INNER JOIN TPM_TASK
ON TPM_TASK.TASKID = TPM_GROUPTASKS.TASKID
INNER JOIN TPM_PROJECTVERSION
ON TPM_TASK.PROJECTID = TPM_PROJECTVERSION.PROJECTID
AND TPM_TASK.VERSIONID = TPM_PROJECTVERSION.VERSIONID
INNER JOIN TPM_TASKSTAGE
ON TPM_TASK.STAGEID = TPM_TASKSTAGE.STAGEID
INNER JOIN TPM_PROJECTSTAGE
ON TPM_PROJECTVERSION.STAGEID = TPM_PROJECTSTAGE.STAGEID
Does it make more sense to you now?, it does to me.
It'd look fine if it had parenthesis in there...
SELECT TPM_TASK.TASKID
FROM
TPM_GROUP
INNER JOIN TPM_USERGROUPS ON TPM_GROUP.GROUPID = TPM_USERGROUPS.GROUPID
INNER JOIN (
TPM_TASK
INNER JOIN TPM_GROUPTASKS ON TPM_TASK.TASKID = TPM_GROUPTASKS.TASKID
INNER JOIN TPM_PROJECTVERSION ON TPM_TASK.PROJECTID = TPM_PROJECTVERSION.PROJECTID
AND TPM_TASK.VERSIONID = TPM_PROJECTVERSION.VERSIONID
INNER JOIN TPM_TASKSTAGE ON TPM_TASK.STAGEID = TPM_TASKSTAGE.STAGEID
INNER JOIN TPM_PROJECTSTAGE ON TPM_PROJECTVERSION.STAGEID = TPM_PROJECTSTAGE.STAGEID
) ON TPM_GROUP.GROUPID = TPM_GROUPTASKS.GROUPID
but since they are all inner joins I agree with Lamak's answer.

Extra row to SELECT statement, crosstab? Access 2007

I'm working with some biostats people and of course they love SAS. I have a select statement below that works for testing the presence of certain problems a person can have. It's a binary thing so they either do or they don't. If a person has heart problem and a respiratory problem, then their patientID will be listed twice. How can I add an extra column of a 1 or 0 for every morbidity? So, if I have three problems and they are "HEART", "LUNG" and "UTI", an extra column would be generated that has a 1 or 0 based on the presence of that a person had that problem or not.
I suppose I can use Excel to make it a crosstab, but eventually it will need to be in that format. Below is my SELECT statement. Thanks, folks!
EDITED:
TRANSFORM First(Person.PersonID) AS Morbidity
SELECT Person.PersonID, Person.Age, Person.Sex
FROM tblKentuckyCounties INNER JOIN ((tblComorbidity INNER JOIN comorbidVisits ON tblComorbidity.ID = comorbidVisits.comorbidFK) INNER JOIN (Person INNER JOIN tblComorbidityPerson ON Person.PersonID = tblComorbidityPerson.personID) ON tblComorbidity.ID = tblComorbidityPerson.comorbidityFK) ON tblKentuckyCounties.ID = Person.County
WHERE (((tblComorbidity.comorbidityexplanation)="anxiety and depression" Or (tblComorbidity.comorbidityexplanation)="heart" Or (tblComorbidity.comorbidityexplanation)="hypertension" Or (tblComorbidity.comorbidityexplanation)="pressure sores" Or (tblComorbidity.comorbidityexplanation)="tobacco" Or (tblComorbidity.comorbidityexplanation)="uti"))
GROUP BY Person.PersonID, Person.Age, Person.Sex, tblComorbidity.comorbidityexplanation
PIVOT Person.Race;
This is not tested:
TRANSFORM IIf([c.comorbidityexplanation]=
[c.comorbidityexplanation],1,0) AS Morbidity
SELECT p.PersonID, p.Age, p.Sex, p.Race
FROM tblKentuckyCounties kc
INNER JOIN ((tblComorbidity c
INNER JOIN comorbidVisits cv
ON c.ID = cv.comorbidFK)
INNER JOIN (Person p
INNER JOIN tblComorbidityPerson cp
ON p.PersonID = cp.personID)
ON c.ID = cp.comorbidityFK)
ON kc.ID = p.County
GROUP BY p.PersonID, p.Age, p.Sex, p.Race
PIVOT c.comorbidityexplanation