JOIN table multiple times for same columns, from different columns - sql-server

I've had a search and there are many Questions out there that sound the same but are slightly not covering what I need.
I have the following setup:
Database: Job1, Table: Document
id | rev_desc_id | created_by_id | modified_by_id | checker_id | approver_id
---|-------------|---------------|----------------|------------|------------
1 | 1 | 1 | 1 | 2 | 3
"rev_desc_id" links MySoftware.dbo.Revision_Description.id
"created_by_id", "modified_by_id", "checker_id", "approver_id" link MyCompany.dbo.Person.id
Database: MyCompany, Table: Person
id | first_name | last_name
---|------------|----------
1 | Tom | DeLonge
2 | Mark | Hoppus
3 | Travis | Barker
Database: MySoftware, Table: Revision_Description
id | name
---|------------
1 | Draft
2 | For Comment
I have the following SQL:
SELECT Document.*, Revision_Description.name AS 'Rev Description', CONCAT(Person.first_name, ' ', Person.last_name) AS 'Created By'
FROM Document
INNER JOIN MySoftware.dbo.Revision_Description
ON rev_desc_id=Revision_Description.id
INNER JOIN MyCompany.dbo.Person
ON created_by_id=Person.id
This all works fine, but I'm now at the point where I need to return the other concatenated names for "modified", "checker" and "approver". I'm not sure how to give these specific column names like "AS Created By".
I also have some other columns that need joining to other tables too.
I am pretty new to database design and I'm not trying my best to name and link them all correctly, so apologies if I'm completely wrong with all this.
Any help or suggestions would be greatly appreciated.
Thank you in advance.

For a lookup tables I prefer to use LEFT JOIN, but you can add the Person table N times and use an alias depending on Creator, Checker, ...
SELECT
Document.*,
Revision_Description.name AS 'Rev Description',
CONCAT(C.first_name, ' ', C.last_name) AS 'Created By',
CONCAT(M.first_name, ' ', M.last_name) AS 'Modified By',
CONCAT(K.first_name, ' ', K.last_name) AS 'Checked By'
FROM Document
INNER JOIN MySoftware.dbo.Revision_Description
ON rev_desc_id=Revision_Description.id
LEFT JOIN MyCompany.dbo.Person as C
ON created_by_id=C.id
LEFT JOIN MyCompany.dbo.Person as M
ON modified_by_id=M.id
LEFT JOIN MyCompany.dbo.Person as K
ON checked_id=K.id

SELECT d.*, s.name 'Rev Description',
CONCAT(c.first_name, ' ', c.last_name) CreatedBy,
CONCAT(m.first_name, ' ', m.last_name) ModifiedBy,
CONCAT(k.first_name, ' ', k.last_name) CheckedBy,
CONCAT(a.first_name, ' ', a.last_name) ApprovedBy,
FROM Document d
JOIN MySoftware.dbo.Revision_Description s
ON s.id = d.rev_desc_id
left JOIN MyCompany.dbo.Person c
ON c.id = d.created_by_id
left JOIN MyCompany.dbo.Person m
ON m.id = d.modified_by_id
left JOIN MyCompany.dbo.Person k
ON k.id = d.checker_id
left JOIN MyCompany.dbo.Person a
ON a.id = d.approver_id

Related

SQL query to get data from two rows connected by key

I have a question that seems very simple to me at first but I'm relatively new to SQL and I can't solve it.
I have two tables: 'Applicants' and 'Family Units'.
Applicants:
ApplicantID | FirstName
----------- | ----------
1 | John
2 | Mary
Family Units:
ApplicantID | UnitID| Note
1 | 10 | Member
2 | 10 | Mother
I need to bring in one table Applicant Name and Mother Name.
Mother applicantID should be determined by having same UnitID in Family Units table and Mother Note in the same table (and other details they are not relevant here).
I tried this query:
That obviously doesn't work correct, I get applicant name instead of applicant's mother's name.
Need you help, links to articles and explanations also will be great because I feel that I'm missing something very basic.
; with cte as
(
select fu.*,a.name from
FamilyUnit fu
join applicant a on a.id = fu.id
where type = 'Mother'
)
select a.id,a.name,c.name
from applicant a
join FamilyUnit fu on fu.id = a.id
join cte c on c.unit = fu.unit
where c.id <> a.id
Im not so sure if this is correct: just try it
select * from
(select * from #family_units where note = 'member') as a
left join
(select * from #family_units where note = 'mother') as b
on a.unitid = b.unitid
left join #applicant_table as c
on a.ApplicantID =c.ApplicantID
Test result:
1 10 Member 2 10 Mother 1 John

SQL Concatenate rows from multiple tables into single text field separated by comma

I have 3 tables
Projects, Consultant, Contact.
The Consultant table is a linking table containing only 3 fields, Projectid, Consultantid, and Contactid, which links a contact to a project as a consultant. There is no direct link from the contact to the project. The full name of the consultant is in the contact table. The Project Number is in the project table.
Project :
ProjectNumber
Contact:
Contactid, Consultant_Full_name
Consultant: Consultantid, Projectid, Contactid
I have built a table in SSRS showing project fields and want to pull in a column on the end showing all the consultants linked to each project
Example -
+---------------+--------------------------------------+
| ProjectNumber | Consultants |
+---------------+--------------------------------------+
| 12356 | Mary White, Fred Bloggs, Peter Jones |
| 12445 | Fred Bloggs, Paul White |
+---------------+--------------------------------------+
The code I have written is:
SELECT t2.ProjectNumber
,consultant = STUFF((
SELECT ',' + fullname
FROM FilteredContact t1
WHERE t1.contactid = t2.ConsultantID
FOR XML PATH('')
), 1, 1, '')
FROM (
SELECT proj.ccx_projectnumber AS ProjectNumber
,link.contactid AS ConsultantID
,con.fullname AS ConsultantName
FROM FilteredContact con
INNER JOIN Filteredccx_ccx_project_contact_consultant AS link ON con.contactid = link.contactid
INNER JOIN Filteredccx_project proj ON link.ccx_projectid = proj.ccx_projectid
) t2
GROUP BY t2.ProjectNumber
I know that this is not grouped correctly as the Contactid needs to be in an aggregate or group by statement but I cannot work out how to do it correctly. I am thinking that maybe I have not linked the tables correctly. If I use
group by ts.ProjectNumber, Contactid
the results are a row per each consultant and not per each project which is what I want.
Any help gratefully accepted.
I am using Sql server 2008
This is what you want
;WITH CTE
AS (
SELECT proj.ccx_projectnumber AS ProjectNumber
,con.fullname AS ConsultantName
FROM Filteredccx_ccx_project_contact_consultant AS link
INNER JOIN Filteredccx_project proj ON link.ccx_projectid = proj.ccx_projectid
INNER JOIN FilteredContact con ON link.contactid = con.contactid
)
SELECT DISTINCT ProjectNumber
,STUFF((
SELECT ',' + ConsultantName
FROM CTE C1
WHERE C.ProjectNumber = C1.ProjectNumber
FOR XML PATH('')
), 1, 1, '')
FROM CTE C

EF6 - Generating unneeded nested queries

I have the following tables:
MAIN_TBL:
Col1 | Col2 | Col3
------------------
A | B | C
D | E | F
And:
REF_TBL:
Ref1 | Ref2 | Ref3
------------------
A | G1 | Foo
D | G1 | Bar
Q | G2 | Xyz
I wish to write the following SQL query:
SELECT M.Col1
FROM MAIN_TBL M
LEFT JOIN REF_TBL R
ON R.Ref1 = M.Col1
AND R.Ref2 = 'G1'
WHERE M.Col3 = 'C'
I wrote the following LINQ query:
from main in dbContext.MAIN_TBL
join refr in dbContext.REF_TBL
on "G1" equals refr.Ref2
into refrLookup
from refr in refrLookup.DefaultIfEmpty()
where main.Col1 == refr.Col1
select main.Col1
And the generated SQL was:
SELECT
[MAIN_TBL].[Col1]
FROM (SELECT
[MAIN_TBL].[Col1] AS [Col1],
[MAIN_TBL].[Col2] AS [Col2],
[MAIN_TBL].[Col3] AS [Col3]
FROM [MAIN_TBL]) AS [Extent1]
INNER JOIN (SELECT
[REF_TBL].[Ref1] AS [Ref1],
[REF_TBL].[Ref2] AS [Ref2],
[REF_TBL].[Ref3] AS [Ref3]
FROM [REF_TBL]) AS [Extent2] ON [Extent1].[Col1] = [Extent2].[Ref1]
WHERE ('G1' = [Extent2].[DESCRIPTION]) AND ([Extent2].[Ref1] IS NOT NULL) AND CAST( [Extent1].[Col3] AS VARCHAR) = 'C') ...
Looks like it is nesting a query within another query, while I just want it to pull from the table. What am I doing wrong?
I may be wrong, but it looks like you don't do the same in linq query and sql query, especially on your left joining clause.
I would go for this, if you want something similar to your sql query.
from main in dbContext.MAIN_TBL.Where(x => x.Col3 == "C")
join refr in dbContext.REF_TBL
on new{n = "G1", c = main.Col1} equals new{n = refr.Ref2, c = refr.Col1}
into refrLookup
from r2 in refrLookup.DefaultIfEmpty()
select main.Col1
By the way, it doesn't make much sense to left join on a table which is not present in the select clause : you will just get multiple identical Col1 if there's more than one related item in the left joined table...

SELECT DISTINCT showing duplicate dates per customer email

I am trying to retrieve information for the past ten months, but am having a couple of errors. First, my query is getting data from as far back as 2013. Secondly, I am seeing duplicates in my results based on the PolEffDate field, like this:
EntityID | PolEffDate | EMail | CustNo | Producer | BusinessPhone
abcde-12345-fghij-67890 | 2013-09-24 | somewhere#email.com | 31000 | Bob Builder | 123-456-7890
abcde-12345-fghij-67890 | 2013-12-01 | somewhere#email.com | 31000 | Bob Builder | 123-456-7890
abcde-12345-fghij-67890 | 2014-09-24 | somewhere#email.com | 31000 | Bob Builder | 123-456-7890
Here is my SQL Query:
SELECT DISTINCT
CONVERT(VarChar(36), Customer.CustId) AS EntityID
, BasicPolInfo.PolEffDate, Customer.EMail, Customer.CustNo
, (isnull(Employee.Firstname + ' ','') + isnull(Employee.LastName,''))
AS Producer, Employee.BusFullPhone
FROM
Customer INNER JOIN BasicPolInfo ON Customer.CustId = BasicPolInfo.CustId INNER JOIN
Transaction ON BasicPolInfo.PolId = Transaction.PolId INNER JOIN
GeneralBranch ON Customer.GLBrnchCode = GeneralBranch.GLBrnchCode INNER JOIN
GeneralDepartment ON Customer.GLDeptCode = GeneralDepartment.GLDeptCode INNER JOIN
GeneralDivision ON Customer.GLDivCode = GeneralDivision.GLDivCode INNER JOIN
Employee ON BasicPolInfo.ExecCode = Employee.EmpCode
WHERE
BasicPolInfo.PolExpDate >= DATEADD(MONTH, -10,CONVERT(VARCHAR(11),GETDATE(),106))
AND BasicPolInfo.PolExpDate <= CONVERT(VARCHAR(11),GETDATE(),106)
AND Customer.Active = 'Y'
AND Customer.typeCust = 'P'
Thank you for the help. I will try my best to answer any questions.
Daniel, the duplication you are seeing is caused because you have multiple records in BasicPolInfo for each CustID value. You can confirm this by running the following query:
SELECT CustID, COUNT(*)
FROM BasicPolInfo
GROUP BY CustID
HAVING COUNT(*) > 1
Depending on your schema, this may not be an issue - after all, there is probably a perfectly legitimate reason for that! Multiple policies per Customer is my guess.
To resolve the duplication, I would recommend a GROUP BY with MIN() or MAX().
Your other issue, that of retrieving data from earlier dates, is because you are selecting the PolEffDate (presumably, policy effective date), but filtering the PolExpDate (presumably, policy expiration date). Which are you intending to use? Policies that have finished sometime in the last ten months could have started much earlier than that.
To resolve the wider date range, reference the same value in your SELECT and WHERE clauses.
Query below (using MAX() and PolExpDate):
SELECT
CONVERT(VarChar(36), Customer.CustId) AS EntityID,
MAX(BasicPolInfo.PolExpDate) AS PolExpDate, -- note that this is now PolExpDate
Customer.EMail,
Customer.CustNo,
(isnull(Employee.Firstname + ' ','') + isnull(Employee.LastName,'')) AS Producer,
Employee.BusFullPhone
FROM
Customer INNER JOIN
BasicPolInfo ON Customer.CustId = BasicPolInfo.CustId INNER JOIN
[Transaction] ON BasicPolInfo.PolId = [Transaction].PolId INNER JOIN
GeneralBranch ON Customer.GLBrnchCode = GeneralBranch.GLBrnchCode INNER JOIN
GeneralDepartment ON Customer.GLDeptCode = GeneralDepartment.GLDeptCode INNER JOIN
GeneralDivision ON Customer.GLDivCode = GeneralDivision.GLDivCode INNER JOIN
Employee ON BasicPolInfo.ExecCode = Employee.EmpCode
WHERE
BasicPolInfo.PolExpDate >= DATEADD(MONTH, -10,CONVERT(VARCHAR(11),GETDATE(),106))
AND BasicPolInfo.PolExpDate <= CONVERT(VARCHAR(11),GETDATE(),106)
AND Customer.Active = 'Y'
AND Customer.typeCust = 'P'
GROUP BY
CONVERT(VarChar(36), Customer.CustId),
Customer.EMail,
Customer.CustNo,
(isnull(Employee.Firstname + ' ','') + isnull(Employee.LastName,'')),
Employee.BusFullPhone

How to retrieve data from two tables related using a third table, SQL Server

I have three tables(simplified)
movie(id int primary key identity, title varchar(20) not null)
genre(id int primary key identity, type varchar(10) not null)
movie_genre(movie_id int references movie(id),
genre_id int references genre(id),
primary key(movie_id, genre_id))
Data in movie
id title
---------------------------
1 | Inception
2 | The Dark Knight
Data in genre
id type
---------------------
1 | action
2 | adventure
3 | thriller
Data in movie_genre
movie_id genre_id
----------------------------
1 | 1
1 | 2
2 | 1
2 | 3
I want to display movie name with its genre types displayed in one column. So, the output would be
title | genres
-----------------------------------------
Inception | action adventure
The Dark Knight | action thriller
I tried to do it in this way
select
movie.title, genre.type
from
movie, genre
where
movie.id = movie_genre.movie_id
and genre.id = movie_genre.genre_id;
but it says :
The multi-part identifier "movie_genre.movie_id" could not be bound.
The multi-part identifier "movie_genre.genre_id" could not be bound.
I am very new to SQL, any help would be appreciated.
Edit :
Using
SELECT G.[Type] ,M.[Title]
FROM movie_genre MG
LEFT JOIN genre G ON MG.genre_id = G.ID
LEFT JOIN movie M ON MG.Movie_ID = M.ID
OR
select movie.title, genre.type
from movie, genre, movie_genre
where
movie.id = movie_genre.movie_id
and genre.id = movie_genre.genre_id;
The output is now,
title | genres
-----------------------------------------
Inception | action
Inception | adventure
The Dark Knight | action
The Dark Knight | thriller
How could I display genres in one row?
SELECT G.[Type]
,M.[Title]
FROM movie_genre MG
LEFT JOIN genre G ON MG.genre_id = G.ID
LEFT JOIN movie M ON MG.Movie_ID = M.ID
To get a list
SELECT DISTINCT M.[Title]
,STUFF((
SELECT ' ' + G.[Type]
FROM genre G INNER JOIN movie_genre MG
ON MG.genre_id = G.ID
WHERE MG.Movie_id = Mov.Movie_id
FOR XML PATH(''),TYPE)
.value('.','NVARCHAR(MAX)'),1,1, '') Genre
FROM movie_genre Mov
INNER JOIN movie M ON Mov.Movie_ID = M.ID
OR
SELECT DISTINCT M.[Title]
,STUFF(List,1,1, '') Genre
FROM #movie_genre Mov
INNER JOIN #movie M
ON Mov.Movie_ID = M.ID
CROSS APPLY
(
SELECT ' ' + G.[Type]
FROM #genre G INNER JOIN #movie_genre MG
ON MG.genre_id = G.ID
WHERE MG.Movie_id = Mov.Movie_id
FOR XML PATH('')
)Gen(List)
SQL FIDDLE
I believe you will need to add the 'movie_genre' to FROM, e.g:
SELECT movie.title, genre.type FROM (movie, genre, movie_genre) WHERE ....

Resources