Left join with multiple inner join - sql

How can we make multiple left and inner join in SQL Server
Following query not returning all Employees because of Inner join
SELECT * from Employee E
LEFT JOIN Participants P on E.EmpID=P.EmpID
INNER JOIN HRDetails H on D. DeptID=H.DeptID
Left JOIN SalaryDetails S on S.participantID=P.participantID

You have used an alias D. which does not refer to any table, this may cause error.
But to answer your question I think inner join would reduce the number of rows if not all DeptID matches between two tables.

Related

Why JOIN LATERAL doesn't unpivot multiple fields

I am very new to postgresql and would really appreciate any help. I am currently using this script (it works fine):
FROM dataset as d
LEFT JOIN metric m on d.datasetid=m.datasetid
LEFT JOIN value v on m.metricid=v.metricid
LEFT JOIN submetric_1 s1 ON v.submetric_1id=s1.submetric_1id
LEFT JOIN submetric_2 s2 ON v.submetric_2id=s2.submetric_2id
LEFT JOIN year y on v.valueid=y.valueid
LEFT JOIN quarter q on v.valueid=q.valueid
LEFT JOIN country c on v.valueid=c.valueid
LEFT JOIN region r on v.valueid=r.valueid
LEFT JOIN county co on v.valueid=co.valueid
LEFT JOIN ladistrict l on v.valueid=l.valueid
This script returns columns from SELECT clause as follows:
metric value […] country region county ladistrict
I need to unpivot four last geographical columns 'country','region','county' and 'ladistrict' to get a return as follows:
metric value […] Geography Geography name
Country Country name
Region Region name
County County name
Ladistrict Ladistrict name
I am trying LATERAL clause as follows:
FROM dataset as d
LEFT JOIN metric m on d.datasetid=m.datasetid
LEFT JOIN value v on m.metricid=v.metricid
LEFT JOIN submetric_1 s1 ON v.submetric_1id=s1.submetric_1id
LEFT JOIN submetric_2 s2 ON v.submetric_2id=s2.submetric_2id
LEFT JOIN year y on v.valueid=y.valueid
LEFT JOIN quarter q on v.valueid=q.valueid
LEFT JOIN LATERAL (VALUES
('Country',c.country)
,('Ladistrict', l.ladistrict)
,('Region', r.region)
, ('County',co.county))
s (Geography, geo_name)
And this one returns error. Please, any ideas how to make it work and get these fields unpivoted? Thanks
A left join needs a join condition. It could be as simple asON TRUE. However, it's easier to just change that left join lateral to a cross join lateral.

Sql join select all values that not availible joined table

is it posssible to select all rows from one table and some rows from other table using join,
here is the what i'm trying to do.
Select CT.COA_TypeId,CT.Code,CT.Types,SUM(GL.Amount) As Amount
from COA_Type CT
join ChartOfAccount CA on CT.COA_TypeId=CA.COA_Id
Join COA_Client CC on CA.COA_Id = CC.COA_Id
JOIN GeneralLedgerLine GL on CC.AccountId=GL.AccountId
Group BY CT.Code,CT.Types,CT.COA_TypeId
i want to select all CT.Types with amount, type rows that do not have Amount i want amount as null
Select CT.COA_TypeId,CT.Code,CT.Types,SUM(GL.Amount) As Amount
from COA_Type CT
INNER join ChartOfAccount CA on CT.COA_TypeId=CA.COA_Id
INNER Join COA_Client CC on CA.COA_Id = CC.COA_Id
LEFT JOIN GeneralLedgerLine GL on CC.AccountId=GL.AccountId
Group BY CT.Code,CT.Types,CT.COA_TypeId
By changing GeneralLedgerLine from an INNER JOIN to a LEFT JOIN, you will still get COA_Type records even though there isn't a matching GeneralLedgerLine.
NOTE: You might have to make the other joins into LEFT JOIN as well.

SQL two multi-row counts in one query

I have got two queries:
select m.name, count(distinct a.kursnr)
from trainer t
left outer join mitarbeiter m
on t.svnr = m.svnr
left outer join einzeltraining e
on t.svnr = e.trainer
left outer join abhaltung a
on t.svnr = a.trainer
group by m.name, t.svnr;
select m.name, count(e.trainer)
from trainer t
left outer join mitarbeiter m
on t.svnr = m.svnr
left outer join einzeltraining e
on e.trainer = t.svnr
group by m.name, e.trainer;
The first one returns the correct number of courses (kursnr) and the second number the correct number of individual classes (einzeltraining) hold by a trainer. However, I cannot make one SQL statement which shows both values in one table. Any help would be appreciated. Thank you.
While there is likely a more efficient way to do this, I wanted to show you the easy way to combine any two queries that share a common field such as this:
select coalesce(q2.name, q1.name) As Name, q1.KursnrCount, q2.TrainerCount
from
( --original first query
select m.name, count(distinct a.kursnr) as KursnrCount
from trainer t
left outer join abhaltung a
on t.svnr = a.trainer
left outer join mitarbeiter m
on t.svnr = m.svnr
left outer join einzeltraining e on svnr = e.trainer
group by m.name, t.svnr
) q1
full join
( --original second query
select count(e.trainer) as TrainerCount, m.name
from trainer t
left outer join einzeltraining e
on e.trainer = t.svnr
left outer join mitarbeiter m
on t.svnr = m.svnr
group by e.trainer, m.name
) q2 on q2.name = q1.name
You could also use an inner join or left join, instead of a full join, depending on how the name fields from those queries match up.

LEFT OUTER JOIN with INNER JOIN

I have a table of students.
and a table of teachers.
SOME of the students (not all) will have a teacher assigned to them.
this is controlled in a 3rd table, matching those students with their teachers, via the studentID and teacherID
what i need the SQL to do, is to LEFT OUTER JOIN onto the 3rd table, which is then INNER JOINED onto the teacher's table (because not all students will appear in the 3rd table, but any teacher that appears in the 3rd table WILL appear in the teachers table).
i am looking to get a result of all student names, and teacher's name, where they are assigned (and null if not).
what i have so far looks like this, and it basically operates as a full INNER JOIN, and does not give me students who do not have teachers assigned:
SELECT firstname, teacherlastName
FROM tblstudents
left outer join [tblStudentRakazot]
ON tblstudents.studentid = [tblStudentRakazot].studentID
INNER JOIN tblteachers
ON [tblStudentRakazot].teacherid = tblteachers.teacherID
can someone pls give me a pointer here? i tried with placing brackets, but that didn't see, to help.
thanks!
You don't use an INNER JOIN but only another LEFT JOIN.
Think of tblStudents as your base. You want to get all of them, not filter anything out, and only attach optional info.
With the first left join, you attach a first info
Student -> TeacherAssignment
The TeacherAssignment can be null or not null.
Now you only attach another info - the teacher's full name pulled from tblTeachers.
Student -> TeacherAssignnent -> TeacherName
Do this with another LEFT JOIN. That attaches the info, where possible, i.e. where TeacherAssignment is not null.
This ignores rows where TeacherAssignment is null anyway.
SELECT firstname, teacherlastName
FROM tblstudents
left outer join
( select * from
[tblStudentRakazot] A INNER JOIN tblteachers B
ON A.teacherid = B.teacherID)AS C
ON tblstudents.studentid = C.studentID
You could move your INNER JOIN to a subquery
SELECT firstname, teacherlastName
FROM tblstudents
LEFT OUTER JOIN
( SELECT [tblStudentRakazot].studentID, tblTeachers.teacherlastName
FROM [tblStudentRakazot]
INNER JOIN tblteachers
ON [tblStudentRakazot].teacherid = tblteachers.teacherID
) teachers
ON tblstudents.studentid = teachers.studentID
Another option is to use a more complicated where clause.
SELECT firstname, teacherlastName
FROM tblstudents
LEFT JOIN [tblStudentRakazot]
ON tblstudents.studentid = [tblStudentRakazot].studentID
LEFT JOIN tblteachers
ON [tblStudentRakazot].teacherid = tblteachers.teacherID
WHERE [tblStudentRakazot] IS NULL
OR tblteachers.teacherID IS NOT NULL
However, SQL Server is pretty good at propogating predicates out of subqueries where it needs to, so I would favour the first approach for both readabilty and efficiency.
EDIT
I did not read the question properly, I thought you did not want records where the teacherID in tblStudentRakazot was NULL. If this is not an issue then you can simply use two LEFT JOINS, without the where clause as above:
SELECT firstname, teacherlastName
FROM tblstudents
LEFT JOIN [tblStudentRakazot]
ON tblstudents.studentid = [tblStudentRakazot].studentID
LEFT JOIN tblteachers
ON [tblStudentRakazot].teacherid = tblteachers.teacherID
SELECT b.student_firstname, teacherlastName
FROM thirdtable a
left join studenttbl b on a.studentid = b.studentid
left join teachertbl b on a.teacherid = b.teacherid
You can always use outer join if you are certain data in teacher table is unique. it will give same result as inner join.
You may not use a subquery as in #GarethD sample.
SELECT firstname, teacherlastName
FROM tblstudents
LEFT OUTER JOIN [tblStudentRakazot]
INNER JOIN tblteachers
ON [tblStudentRakazot].teacherid = tblteachers.teacherID
ON tblstudents.studentid = [tblStudentRakazot].studentID
But when looking more deeply execution plans of this query and query with subquery will likely be equivalent.

Assigning an alias to a table made by a join

I am joining 3 tables as shown below -
select *
from Employee as e inner join [Grant] as g
on e.EmpID = g.EmpID -- "virtual table"
inner join Location as l
on l.LocationID = e.LocationID
Code from select to GrantID seems to be a "virtual table". So, it can be joined with another table (Location) to perform a 3 table join. I want to give this virtual table an alias. Is that possible ? If yes, then how do i do it ?
NOTE -
i use sql server 2008 express
Can't you just do this?
SELECT <columns>
FROM (SELECT <columns 2> FROM Employee as e INNER JOIN [Grant] as g on e.EmpID = g.EmpID) as t1
INNER JOIN Location as l on t1.LocationID = l.LocationID
I don't know what columns you're trying to select, thus the placeholder.
How about a CTE (Common Table Expression)? Like this:
WITH my_cte
AS ( SELECT e.EmpID as e_EmpID, g.* -- expand column list to only include required columns
FROM Employee AS e
INNER JOIN [Grant] AS g ON e.EmpID = g.EmpID -- "virtual table"
)
SELECT *
FROM my_cte
INNER JOIN Location AS l ON l.LocationID = my_cte.LocationID;
Just know that if you refer to a CTE multiple times in the subsequent query the entire query is re-executed. If you need to refer to the CTE multiple times consider storing the results in a temp table first, then executing your query to join against the temp table.
Perhaps this will do.
select *
from (select * from Employee as e
inner join [Grant] as g on e.EmpID = g.EmpID) as vt
inner join Location as l on l.LocationID = vt.LocationID
Just make sure that column names do not repeat themselves in Employee and Grant.