SQL join to many rows - sql

I have a sql Query with a lot of queries.
But i will try to make it simple
Table.Result
Id
Result
Table.ResultGender
ResultID
GenderID
Table.Gender
Id
Gender
One result can have more than one gender.
So want a result like this
Result | Gender
Some result | Female
Another result | Female, male
But i'm getting
Result | Gender
Some result | Female
Another result | male
Another result | Female
Query:
SELECT Gender.Name , Result.Result
FROM Gender
LEFT OUTER JOIN ResultGender ON Gender.Id = ResultGender.GenderId
LEFT OUTER JOIN Result ON ResultGender.ResultId = Result.Id
UPDATE
I have tried this
SELECT Gender.Name , Result.Result ,
STUFF((SELECT ',' + Name
FROM Gender
WHERE (Id = Gender_1.Id) FOR XML PATH(''))as varchar(max)) AS test
FROM Gender AS Gender_1
LEFT OUTER JOIN ResultGender ON Gender_1.Id = ResultGender.GenderId
LEFT OUTER JOIN Result ON ResultGender.ResultId = Result.Id
AND THIS in SQL manager
SELECT Gender.Name , Result.Result ,
CAST((SELECT ',' + Name
FROM Gender
WHERE (Id = Gender_1.Id) FOR XML PATH(''))as varchar(max)) AS test
FROM Gender AS Gender_1
LEFT OUTER JOIN ResultGender ON Gender_1.Id = ResultGender.GenderId
LEFT OUTER JOIN Result ON ResultGender.ResultId = Result.Id
BOTH are trying to save a RPT file

Try in following:
DECLARE #Result VARCHAR(8000)
SELECT Gender.Name, #Result = COALESCE(#Result + ', ', '') + Result.Result
FROM Gender
JOIN Result ON Gender.Id = Result.Id
JOIN ResultGender ON Gender.Id = ResultGender.GenderId
AND StudyResult.Id = ResultGender.ResultId

You are joining incorrectly. Gender.Id is the ID of a Gender record, and Result.Id is the ID of a Result record. Hence Gender.Id = Result.Id makes no sense. ResultGender is the brige table you need for the join: Gender -> GenderResult -> Result.
As to your actual request: Group by Result in order to get one record per Result. Get your Gender list with an appropriate function (I'm showing it here with MySQL's GROUP_CONCAT.)
select
r.result
group_concat(g.name)
from result r
inner join resultgender rg on rg.resultid = r.id
inner join gender g on g.id = rg.genderid
group by r.result;
Unfortunately SQL Server doesn't provide such function as GROUP_CONCAT. It needs some fumbling with XML PATH and STUFF instead. See here: How to make a query with group_concat in sql server.
In case you have Results without a Gender, use outer joins instead:
left join resultgender rg on rg.resultid = r.id
left join gender g on g.id = rg.genderid

Related

JOIN AND CASE MORE AN TABLE

I have 2 tables; the first one ORG contains the following columns:
ORG_REF, ARB_REF, NAME, LEVEL, START_DATE
and the second one WORK contains these columns:
ARB_REF, WORK_STREET - WORK_NUM, WORK_ZIP
I want to do the following: write a select query that search in work and see if the WORK_STREET, WORK_ZIP are duplicate together, then you should look at WORK_NUM. If it is the same then output value ' ok ', but if WORK_NUM is not the same, output 'not ok'
I wrote this SQL query:
select
A.ARB_REF, A.WORK_STREET, A.WORK_NUM, A.WORK_ZIP
case when B.B = 1 then 'OK' else 'not ok' end
from
work A
join
(select
WORK_STREET, WORK_ZIP count(distinct , A.WORK_NUM) B
from
WORK
group by
WORK_STREET, WORK_ZIP) B on B.WORK_STREET = A.WORK_STREET
and B.WORK_ZIP = A.WORK_ZIP
Now I want to join the table ORG with this result I want to check if every address belong to org if it belong I should create a new column result and set it to yes in it (RESULT) AND show the "name" column otherwise set no in 'RESULT'.
Can anyone help me please?
While you can accomplish your result by adding a left outer join to the query you've already started, it might be easiest to just use count() over....
with org_data as (
-- do the inner join before the left join later
select * from org1 o1 inner join org2 o2 on o2.orgid = o1.orgid
)
select
*,
count(*) over (partition by WORK_STREET, WORKZIP) as cnt,
case when o.ARB_REF is not null then 'Yes' else 'No' end as result
from
WORK w left outer join org_data o on o.ARB_REF = w.ARB_REF

Left join statement has no column 'client'

I am trying to append a column to the right
SELECT
'abc' as client,
sum(nested.freq) as freq,
FROM
(
SELECT
uh.route
COUNT(uh.route) as freq
FROM
employee AS up,
hist AS uh
where
up.id = uh.eID
AND uh.PrhEEBankRoute = '123'
GROUP BY
uh.route
) AS nested
LEFT JOIN (
SELECT
'abc' as client,
sum(raw.freq) as total_trans
FROM
(
SELECT
uh.route,
COUNT(uh.route) as freq
FROM
employee AS up,
hist AS uh
where
up.id = uh.eID
GROUP BY
uh.route
) AS raw
) raw2 ON raw2.client = nested.client;
The expected result is something like this
client | freq | total_trans
abc | 2 | 100
But I am getting the following error:
left join statement has no column 'client'
The first subquery, aliased as "nested" is:
SELECT
uh.route --<< no column called "client"
, COUNT(uh.route) AS freq --<< no column called "client"
FROM employee AS up
, hist AS uh
WHERE up.id = uh.eID
AND uh.PrhEEBankRoute = '123'
GROUP BY uh.route
In the next subquery at the join condition you refer to nested.client
) raw2 ON raw2.client = nested.client;
That column does not exist in the nested subquery, so the error message is accurate.

SQL SELECT from and EAV table

Based on my previous questions I have this following tables:
IrisColor
ID Description
1 Blue
2 Gray
3 Green
4 Brown
SkinColor
ID Description
1 White
2 Asian
3 Dark
Gender
ID Description
1 Male
2 Female
And the Attributes table
Attributes
ID Description
1 SkinColor
2 IrisColor
3 Gender
And also the EAV table:
PersonDetails
PersonID AttributeID ValueID
121 1 1
121 2 2
121 3 1
122 1 2
122 2 1
122 3 1
So if I would want to select the Name, the attribute name and value for only the SkinColor I would do something like this:
SELECT p.Name,
a.Description,
v.Description
FROM PersonDetails AS sd
INNER JOIN Subjects AS p ON sd.PersonID=p.ID
INNER JOIN SubjectAttributes AS a ON sd.AttributeID=a.ID
INNER JOIN SkinColor AS v ON sd.ValueID= v.ID
But what should I do If I would want to select all the information for all of the persons from the database, not only skin color but iris color and gender too?
Previously I knew that from SkinColor I wanted to select that value, but in the PersonDetails I also have Values for IrisColor and Gender.
INNER JOIN SkinColor AS v ON sd.ValueID= v.ID this won't be appropriate anymore. How to replace this with something more dynamical?
Update:
I used this statement:
SELECT
SubjectID,
SkinColor,
IrisColor,
EyeLidFlisure,
KnownEyeDeffect,
Ethnicity,
Height,
DrivingLicense,
Gender
FROM
(
SELECT SubjectID, attr.Description as attribute, ValueID from SubjectDetails, SubjectAttributes as attr WHERE SubjectDetails.AttributeID=attr.ID
) as t
PIVOT(MAX(ValueID) FOR attribute IN (SkinColor,IrisColor,Gender,EyeLidFlisure,KnownEyeDeffect,Ethnicity,Height,DrivingLicense)) AS t1
Now, I have all the attributes listed in separate columns, but instead of Value description I have Value ID. How should I continue?
Guess you need dynamic sql built from attributes dictionary
declare #sql varchar(max)=
'select PersonID , ' +
+ stuff((select ','+Description + '.Description as ' + Description
from Attributes
for xml path ('')),1,1,'')
+ ' from (select PersonID, '
+ stuff((select ',max(case AttributeID when ' + cast(ID as varchar(5)) +' then ValueID end) as ' + Description
from Attributes
for xml path ('')),1,1,'')
+' from PersonDetails group by PersonID ) pvt'
+ (select ' left join ' + Description + ' on pvt.' + Description + ' = '+ Description + '.ID'
from Attributes
for xml path (''));
exec (#sql);
Your data model is a bit arcane, because you have ids in the "person details" table that cannot have proper foreign key relationships. You could put all the attributes in the same table. Or have a separate table for each attribute. Or -- as is common with EAV models -- put the descriptions directly into PersonDetails.
You are going to need to do something like this:
SELECT p.Name,
sa.Description,
ic.Description as IrisColor,
g.Description as gender
FROM PersonDetails sd INNER JOIN
Subjects p
ON sd.PersonID = p.ID INNER JOIN
SubjectAttributes sa
ON sd.AttributeID = sa.ID
ON LEFT JOIN
SkinColor sc
ON sd.ValueID = sc.ID AND sa.Description = 'SkinColor' LEFT JOIN
IrisColor ic
ON sd.ValueId = ic.ID AND sa.Description = 'IrisColor' LEFT JOIN
Gender g
ON sd.ValueId = g.ID AND sa.Description = 'Gender';
This would be the complete solution (don't know if it is the easiest one.. but it works)
WITH Subject AS (
SELECT
SubjectID,
SkinColor,
IrisColor,
EyeLidFlisure,
KnownEyeDeffect,
Ethnicity,
Height,
DrivingLicense,
Gender
FROM
(
SELECT SubjectID, attr.Description as attribute, ValueID from SubjectDetails, SubjectAttributes as attr WHERE SubjectDetails.AttributeID=attr.ID
) as t
PIVOT(MAX(ValueID) FOR attribute IN (SkinColor,IrisColor,Gender,EyeLidFlisure,KnownEyeDeffect,Ethnicity,Height,DrivingLicense)) AS t1
)
SELECT SubjectID,
whole.Name as Name,
whole.eMail as eMail,
skincolor.Description as SkinColor,
iriscolor.Description as IrisColor,
eyelid.Description as EyeLidFlisure,
defect.Description as KnownEyeDeffect,
eth.Description as Ethnicity,
height.Description as Height,
dl.Description as DrivingLicense,
gender.Description as Gender
FROM Subject S
Left JOIN Subjects whole ON whole.ID=S.SubjectID
Left JOIN SkinColor skincolor ON S.SkinColor=skincolor.ID
Left JOIN IrisColor iriscolor ON S.IrisColor=iriscolor.ID
Left JOIN EyeLidFlisure eyelid ON S.EyeLidFlisure=eyelid.ID
Left JOIN KnownEyeDeffect defect ON S.KnownEyeDeffect=defect.ID
Left JOIN Ethnicity eth ON S.Ethnicity=eth.ID
Left JOIN Height height ON S.Height=height.ID
Left JOIN DrivingLicense dl ON S.DrivingLicense=dl.ID
Left JOIN Gender gender ON S.Gender=gender.ID

MySql scoping problem with correlated subqueries

I'm having this Mysql query, It works:
SELECT
nom
,prenom
,(SELECT GROUP_CONCAT(category_en) FROM
(SELECT DISTINCT category_en FROM categories c WHERE id IN
(SELECT DISTINCT category_id FROM m3allems_to_categories m2c WHERE m3allem_id = 37)
) cS
) categories
,(SELECT GROUP_CONCAT(area_en) FROM
(SELECT DISTINCT area_en FROM areas c WHERE id IN
(SELECT DISTINCT area_id FROM m3allems_to_areas m2a WHERE m3allem_id = 37)
) aSq
) areas
FROM m3allems m
WHERE m.id = 37
The result is:
nom prenom categories areas
Man Multi Carpentry,Paint,Walls Beirut,Baalbak,Saida
It works correclty, but only when i hardcode into the query the id that I want (37).
I want it to work for all entries in the m3allem table, so I try this:
SELECT
nom
,prenom
,(SELECT GROUP_CONCAT(category_en) FROM
(SELECT DISTINCT category_en FROM categories c WHERE id IN
(SELECT DISTINCT category_id FROM m3allems_to_categories m2c WHERE m3allem_id = m.id)
) cS
) categories
,(SELECT GROUP_CONCAT(area_en) FROM
(SELECT DISTINCT area_en FROM areas c WHERE id IN
(SELECT DISTINCT area_id FROM m3allems_to_areas m2a WHERE m3allem_id = m.id)
) aSq
) areas
FROM m3allems m
And I get an error:
Unknown column 'm.id' in 'where
clause'
Why?
From the MySql manual:
13.2.8.7. Correlated Subqueries
[...]
Scoping rule: MySQL evaluates from inside to outside.
So... do this not work when the subquery is in a SELECT section? I did not read anything about that.
Does anyone know? What should I do? It took me a long time to build this query... I know it's a monster query but it gets what I want in a single query, and I am so close to getting it to work!
Can anyone help?
You can only correlate one level deep.
Use:
SELECT m.nom,
m.prenom,
x.categories,
y.areas
FROM m3allens m
LEFT JOIN (SELECT m2c.m3allem_id,
GROUP_CONCAT(DISTINCT c.category_en) AS categories
FROM CATEGORIES c
JOIN m3allems_to_categories m2c ON m2c.category_id = c.id
GROUP BY m2c.m3allem_id) x ON x.m3allem_id = m.id
LEFT JOIN (SELECT m2a.m3allem_id,
GROUP_CONCAT(DISTINCT a.area_en) AS areas
FROM AREAS a
JOIN m3allems_to_areas m2a ON m2a.area_id = a.id
GROUP BY m2a.m3allem_id) y ON y.m3allem_id = m.id
WHERE m.id = ?
The reason for the error is that in the subquery m is not defined. It is defined later in the outer query.

SQL JOIN and WHERE statement

I have a problem getting this sql statemen to return what I want:
I want it to return a list of properties both the employee or Job_Profile. If one of them do not have the property it should return NULL in that row/column
Now the sql looks like:
SELECT Parameter.Patameter_Description ParamName,
Job_Profile.Title, Job_Property.Mark JobMark,
Emp_Property.Mark EmpMark,
Emp_Id--, (Employee.First_Name + ' ' + Employee.Last_Name) EmpName
FROM Job_Property
INNER JOIN Job_Profile ON Job_Profile.Title = Job_Property.Job_Title
INNER JOIN Parameter ON Job_Property.Parameter_Id = Parameter.Id
RIGHT JOIN Emp_Property ON Emp_Property.Parameter_Id = Job_Property.Parameter_Id
INNER JOIN Employee ON Emp_Property.Emp_Id = Employee.Enterprise_Staff_Id
WHERE Employee.Enterprise_Staff_Id = 22
AND Job_Profile.Title =
(SELECT
Employee.Job_Profile_Name
FROM Employee WHERE Employee.Enterprise_Staff_Id = 22)
The result is:
Analyse test 1 3 22
And I would like it to be something like this:
Analyse test 1 3 22
Data test 3 NULL NULL or 22
economic test 4 NULL NULL or 22
Service test 2 NULL NULL or 22
I know there is a problem when I:
- join Emp_Property
- Make the WHERE statement
Try LEFT OUTER JOIN when joining Emp_Property
I found a solution, I had to make temp tables and join them:
CREATE TABLE #CompareJob
(Parameter_Id INT
,Parameter_Name VARCHAR(MAX)
,Jobprofile VARCHAR(30)
,Job_Mark INT
)
INSERT INTO #CompareJob(Parameter_Id,Parameter_Name, Jobprofile ,Job_Mark)
SELECT Parameter.Id, Parameter.Patameter_Description, Job_Profile.Title, Job_Property.Mark
FROM Job_Property
INNER JOIN Job_Profile ON Job_Profile.Title = Job_Property.Job_Title
INNER JOIN Parameter ON Job_Property.Parameter_Id = Parameter.Id
WHERE Job_Profile.Title = (SELECT Employee.Job_Profile_Name FROM Employee WHERE Employee.Enterprise_Staff_Id = 22)
CREATE TABLE #CompareEmp
(Parameter_Id INT
,Parameter_Name VARCHAR(MAX)
,Emp_Id INT
,Emp_Name VARCHAR(100)
,Emp_Mark INT
)
INSERT INTO #CompareEmp(Parameter_Id,Parameter_Name, Emp_Id , Emp_Name ,Emp_Mark)
SELECT Parameter.Id, Parameter.Patameter_Description, Employee.Enterprise_Staff_Id, (Employee.First_Name + ' ' + Employee.Last_Name) empname, Emp_Property.Mark
FROM Emp_Property
INNER JOIN Employee ON Employee.Enterprise_Staff_Id = Emp_Property.Emp_Id
INNER JOIN Parameter ON Parameter.Id = Emp_Property.Parameter_Id
WHERE Employee.Enterprise_Staff_Id = 22
SELECT * FROM #CompareJob
FULL OUTER JOIN #CompareEmp ON #CompareJob.Parameter_Id = #CompareEmp.Parameter_Id
Agree with Danny, use the 'LEFT OUTER JOIN' method instead of 'INNER JOIN' as this will only return rows where an entry is found in both tables.