dbTalk Databases Forums  

Joining from 2 different tables

comp.databases.ms-sqlserver comp.databases.ms-sqlserver


Discuss Joining from 2 different tables in the comp.databases.ms-sqlserver forum.



Reply
 
Thread Tools Display Modes
  #1  
Old   
tshad
 
Posts: n/a

Default Joining from 2 different tables - 10-21-2010 , 07:57 PM






I can't seem to get this query to work. I have a set of tables where I have
questions in one table. Each question can have multiple possible answers.
Either employees or customers can answer the questions.

What I need is a row for each question answered and the person that answered
it. If both an employee and a customer answered the question then I should
have 2 rows.

But if there is an answer that no one answered, that answer shouldn't show.

The following are not the actual tables but just an example of what I am
trying to do.

CREATE TABLE Questions
(
QuestionID int,
QuestionText varchar(2000)
)

CREATE TABLE Answers
(
AnswersID int,
QuestionID int,
AnswerText varchar(2000)
)

CREATE TABLE Employees
(
EmployeeID int
FirstName varchar(30),
LastName
)

CREATE TABLE EmployeeAnswerMap
(
EmployeeAnswerMapID int,
EmployeeID int,
AnswerID int
)

CREATE TABLE Customers
(
CustomerID int
FirstName varchar(30),
LastName
)

CREATE TABLE CustomerAnswerMap
(
CustomerAnswerMapID int,
CustomerID int,
AnswerID int
)

I could do it this way, where the 1st query gets me all the answers that the
Employee answered and the 2nd one gets me all the answers that a Customer
answered:

SELECT FirstName, LastName, QuestionText, AnswerText
FROM Questions Q
JOIN Answers A ON A.QuestionID = Q.QuestionID
JOIN EmployeeAnswerMap EAM.AnswerID = A.AnswerID
JOIN Employees E ON E.EmployeeID = EAM.EmplyeeID
UNION ALL
SELECT FirstName, LastName, QuestionText, AnswerText
FROM Questions Q
JOIN Answers A ON A.QuestionID = Q.QuestionID
JOIN CustomerAnswerMap CAM.AnswerID = A.AnswerID
JOIN Customers C ON C.CustomerID = CAM.CustomerID

But I was trying to do it withoug a UNION. Maybe you can't.

If I do the following I only get the ones that match both the employee and
customer.

SELECT FirstName, LastName, QuestionText, AnswerText
FROM Questions Q
JOIN Answers A ON A.QuestionID = Q.QuestionID
JOIN EmployeeAnswerMap EAM.AnswerID = A.AnswerID
JOIN Employees E ON E.EmployeeID = EAM.EmplyeeID
JOIN CustomerAnswerMap CAM.AnswerID = A.AnswerID
JOIN Customers C ON C.CustomerID = CAM.CustomerID

You can't do left join on either the EmployeeAnswerMap or the
CustomerAnswerMap or you would get all the answers whether anybody answered
them or not.

What I am looking for are the answers that either an employee or a customer
(or both) have answered.

Thanks,

Tom.

Reply With Quote
  #2  
Old   
Erland Sommarskog
 
Posts: n/a

Default Re: Joining from 2 different tables - 10-23-2010 , 04:50 AM






tshad (tfs (AT) dslextreme (DOT) com) writes:
Quote:
That was what I tried.

But I don't seem to get all of them.

If I do a UNION, I get 11 records. If I do each separately, I get 6 for
employees and 5 for customers.

But if I do the left Joins, I am only getting 7 records.

Can't figure out why that is not getting the other 4.
I think you are, but if I get this right you get them them columnwise,
rather than rowwise. To get them rowwise, you need to unpivot. This
may be possible by cross-joining with this table

(SELECT 1 AS n UNION ALL SELECT 2) AS u

And then do some CASE acrobatics. Since you did not provide any sample
data, I abstain from trying a full query.

After all, the UNION query seems a lot simpler.


--
Erland Sommarskog, SQL Server MVP, esquel (AT) sommarskog (DOT) se

Links for SQL Server Books Online:
SQL 2008: http://msdn.microsoft.com/en-us/sqlserver/cc514207.aspx
SQL 2005: http://msdn.microsoft.com/en-us/sqlserver/bb895970.aspx

Reply With Quote
  #3  
Old   
Roger
 
Posts: n/a

Default Re: Joining from 2 different tables - 10-25-2010 , 10:15 AM



"tshad" <tfs (AT) dslextreme (DOT) com> wrote

Quote:
That was what I figured but was curious if there was a better way,
performance wise.

I have 2 queries I need to do. One like the one I just did and one that
also shows the rows that didn't have any answers.

If I was doing it without the UNION, I would just look at rows with nulls
in both sets of columns.

But what is the best way using a UNION?

Do you mean questions without any answers, or answers that have not been
chosen?

If the former, here's one way of doing it.
Select the union of all questions that have been answered by customer or
empoyee
Then exclude those questions from the result

SELECT q.QuestionID, q.QuestionText
FROM Questions q LEFT JOIN
( SELECT a.QuestionID
FROM Answers a INNER JOIN
EmployeeAnswerMap AS eam
ON a.AnswersID = eam.AnswerID
UNION
SELECT a.QuestionID
FROM Answers a INNER JOIN
CustomerAnswerMap AS cam
ON a.AnswersID = cam.AnswerID)
AS ans ON q.QuestionID = ans.QuestionID
WHERE (ans.QuestionID IS NULL)

You could simplify things a lot if you had just one answermap table.

Then either
1. have two columns for customerid and employeeid, and join on one or the
other as required to get the customer/employee names
or
2. have one table for both customers and employees, and add a field to tell
which is which

--
Roger

Reply With Quote
  #4  
Old   
tshad
 
Posts: n/a

Default Re: Joining from 2 different tables - 10-25-2010 , 11:01 AM



"Roger" <mothland (AT) btopenworld (DOT) com> wrote

Quote:
"tshad" <tfs (AT) dslextreme (DOT) com> wrote in message
news:q5gxo.6227$yw.2591 (AT) newsfe18 (DOT) iad...
That was what I figured but was curious if there was a better way,
performance wise.

I have 2 queries I need to do. One like the one I just did and one that
also shows the rows that didn't have any answers.

If I was doing it without the UNION, I would just look at rows with nulls
in both sets of columns.

But what is the best way using a UNION?


Do you mean questions without any answers, or answers that have not been
chosen?

By the former, I assume you mean questions where none of the answers have
been chosen.

So in my example, I would get an empty set. But if I add the following
records:

INSERT Questions(QuestionText) VALUES ('Which is your favorite sport?');
INSERT Answers (QuestionID,AnswerText) VALUES (1,'Football');
INSERT Answers (QuestionID,AnswerText) VALUES (1,'Baseball');
INSERT Answers (QuestionID,AnswerText) VALUES (1,'Basketball');
INSERT Answers (QuestionID,AnswerText) VALUES (1,'Other');

Then I get "Which is your favorite sport?", which would be correct.

Answers that no one has chosen (in my case that would have been Blue for the
original question and the all 4 answers for the new question since no one
had answered it) would also be useful.

Quote:
If the former, here's one way of doing it.
Select the union of all questions that have been answered by customer or
empoyee
Then exclude those questions from the result

SELECT q.QuestionID, q.QuestionText
FROM Questions q LEFT JOIN
( SELECT a.QuestionID
FROM Answers a INNER JOIN
EmployeeAnswerMap AS eam
ON a.AnswersID = eam.AnswerID
UNION
SELECT a.QuestionID
FROM Answers a INNER JOIN
CustomerAnswerMap AS cam
ON a.AnswersID = cam.AnswerID)
AS ans ON q.QuestionID = ans.QuestionID
WHERE (ans.QuestionID IS NULL)

You could simplify things a lot if you had just one answermap table.

I agree - but the second table was added by someone else.

Quote:
Then either
1. have two columns for customerid and employeeid, and join on one or the
other as required to get the customer/employee names
or
2. have one table for both customers and employees, and add a field to
tell which is which

Or have a 2nd UNION where this query is added to the original union.

Thanks,

Tom

Quote:
--
Roger


Reply With Quote
  #5  
Old   
Roger
 
Posts: n/a

Default Re: Joining from 2 different tables - 10-25-2010 , 12:31 PM



"tshad" <tfs (AT) dslextreme (DOT) com> wrote

Quote:
"Roger" <mothland (AT) btopenworld (DOT) com> wrote in message
news:v_SdnZAQYr2PAljRnZ2dnUVZ8sCdnZ2d (AT) bt (DOT) com...
"tshad" <tfs (AT) dslextreme (DOT) com> wrote in message
news:q5gxo.6227$yw.2591 (AT) newsfe18 (DOT) iad...
That was what I figured but was curious if there was a better way,
performance wise.

I have 2 queries I need to do. One like the one I just did and one that
also shows the rows that didn't have any answers.

If I was doing it without the UNION, I would just look at rows with
nulls in both sets of columns.

But what is the best way using a UNION?


Do you mean questions without any answers, or answers that have not been
chosen?

By the former, I assume you mean questions where none of the answers have
been chosen.


Yes

Quote:
So in my example, I would get an empty set. But if I add the following
records:

INSERT Questions(QuestionText) VALUES ('Which is your favorite sport?');
INSERT Answers (QuestionID,AnswerText) VALUES (1,'Football');
INSERT Answers (QuestionID,AnswerText) VALUES (1,'Baseball');
INSERT Answers (QuestionID,AnswerText) VALUES (1,'Basketball');
INSERT Answers (QuestionID,AnswerText) VALUES (1,'Other');

Then I get "Which is your favorite sport?", which would be correct.

Answers that no one has chosen (in my case that would have been Blue for
the original question and the all 4 answers for the new question since no
one had answered it) would also be useful.
That's probably easier without a union

select whatever from answers a
left join employeeanswermap eam on a.answersid = eam.answerid
left join customeranswermap cam on a.answersid = cam.answerid
where cam.customeranswermapid is null and eam.employeeanswermapid is null


Quote:
You could simplify things a lot if you had just one answermap table.


I agree - but the second table was added by someone else.

Isn't that always the way

Roger

Reply With Quote
  #6  
Old   
Erland Sommarskog
 
Posts: n/a

Default Re: Joining from 2 different tables - 10-26-2010 , 02:18 AM



tshad (tfs (AT) dslextreme (DOT) com) writes:
Quote:
That does work as well. Not sure why. I will have to look closer at it.
Especially since I am not quite sure how the cross join works here.
Actually, it is worth to take a look it. For this particular problem, the
query is overly complicated, but the technique as such comes to use at
times. That is, when you need to convert column to rows, the typical
technique is to cross join with a small table of constants and then use
these constants to control CASE expressions. (There is also the UNPIVOT
keyword, but I've learnt that syntax very well.)

Quote:
1) The way I written the LEFT JOINs is the "right" way of doing an
inner join from a left-joined table.

Not sure what you mean here.
When you have:

LEFT JOIN EmployeeAnswerMap EAM ON EAM.AnswerID = A.AnswersID
JOIN Employees E ON E.EmployeeID = EAM.EmployeeID

You are effectively transforming the outer join to an inner join, because
the join to Employees filters out rows where EAM.AnswerID is NULL. Your
remedy was to use a second LEFT JOIN. That works too in this case, but
there are situations where this give a different result. (Which may be
considered far-fetch corner cases.)



--
Erland Sommarskog, SQL Server MVP, esquel (AT) sommarskog (DOT) se

Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pro...ads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodinf...ons/books.mspx

Reply With Quote
Reply




Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.3
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.