Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase 12»»

Simple LEFT JOIN question Expand / Collapse
Author
Message
Posted Monday, October 01, 2012 1:14 PM
Right there with Babe

Right there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with Babe

Group: General Forum Members
Last Login: 2 days ago @ 6:44 AM
Points: 759, Visits: 802
I've got two tables Curriculum and UserCurriculum. I want to list all classes for each user and show nulls where the user hasn't taken the class.

[LMS].[Curriculum]
[CurriculumKey] [int] IDENTITY(1,1) NOT NULL,
[CurriculumName] [varchar](255) NOT NULL,
[CustomerServiceCourse] [bit] NULL,
[FranchiseCourse] [bit] NULL,
[ManagerCourse] [bit] NULL,
[CurriculumType] [varchar](25) NULL

[LMS].[UserCurriculum]
[Username] [varchar](255) NOT NULL,
[CurriculumKey] [int] NOT NULL,
[CompletionDateKey] [int] NOT NULL,
[FranchiseKey] [int] NOT NULL

Sounds simple enough; do a left join like:

SELECT c.*,
uc.*
FROM LMS.Curriculum c
LEFT OUTER JOIN LMS.UserCurriculum uc ON c.CurriculumKey = uc.CurriculumKey
ORDER BY CompletionDateKey;

But this returns back just the number of rows in the UserCurriculum.

What obvious thing am I missing?

Thanks,
Rob
Post #1366725
Posted Monday, October 01, 2012 1:19 PM


SSCoach

SSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoach

Group: General Forum Members
Last Login: 2 days ago @ 1:45 PM
Points: 15,442, Visits: 9,572
Have you verified that there are rows that should show no-join to that table?

- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread

"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
Post #1366728
Posted Monday, October 01, 2012 1:24 PM
Right there with Babe

Right there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with Babe

Group: General Forum Members
Last Login: 2 days ago @ 6:44 AM
Points: 759, Visits: 802
Yes, I can have one particular test user that has taken 9 of the 15 classes from the Curriculum table.
Post #1366735
Posted Monday, October 01, 2012 1:32 PM


SSCoach

SSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoach

Group: General Forum Members
Last Login: 2 days ago @ 1:45 PM
Points: 15,442, Visits: 9,572
The query is backwards for that. The left join you defined would find a curriculum that has never had any users, not the other way around.

- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread

"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
Post #1366739
Posted Monday, October 01, 2012 1:44 PM
Right there with Babe

Right there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with Babe

Group: General Forum Members
Last Login: 2 days ago @ 6:44 AM
Points: 759, Visits: 802
Okay, but if I switch to a right join I still get the total number of rows from the UserCurriculum table.
SELECT c.*,
uc.*
FROM LMS.Curriculum c
RIGHT OUTER JOIN LMS.UserCurriculum uc ON c.CurriculumKey = uc.CurriculumKey
ORDER BY CompletionDateKey;

Thinking outloud here: So the first select returned back all rows because each class has at least one user that has taken the class. The second select returned back all rows because each user had taken at least one class.

I probably didn't explain what I was after, but I'm looking for users that haven't taken all (15) of the classes from the Curriculum table.

So my first thought is get a cartesian product with a full outer join and then look for Null Curriculum keys.
SELECT c.*,
uc.*
FROM LMS.Curriculum c
FULL OUTER JOIN LMS.UserCurriculum uc ON c.CurriculumKey = uc.CurriculumKey
ORDER BY CompletionDateKey;

But that still gives me the same count as the left and right outer joins. Hmmmm.
Post #1366747
Posted Monday, October 01, 2012 2:04 PM


SSCoach

SSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoachSSCoach

Group: General Forum Members
Last Login: 2 days ago @ 1:45 PM
Points: 15,442, Visits: 9,572
Do you have a Users table? If so, you need to start from that, then join to UsersCurriculum and then Curriculum.

Otherwise, you don't have a full list of users.

If you want all users joined to all curriculae, then it's a Cross Join from Users to Curriculum, then an outer join from there to UsersCurriculum. That will give you all Users, all Curiculums, and a Null if they've never done it, or a value if they have.


- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread

"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
Post #1366754
Posted Monday, October 01, 2012 2:25 PM
Right there with Babe

Right there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with Babe

Group: General Forum Members
Last Login: 2 days ago @ 6:44 AM
Points: 759, Visits: 802
Thank you for breaking that down for me. No users table, but I can do:

;WITH CTE_Users (Username)
AS
(
SELECT DISTINCT Username
FROM LMS.UserCurriculum
)
SELECT c.*,
u.*,
uc.*
FROM LMS.Curriculum c
CROSS JOIN CTE_Users u
LEFT JOIN LMS.UserCurriculum uc ON uc.Username = u.Username AND uc.CurriculumKey = c.CurriculumKey
WHERE u.Username = 'TestUser' AND uc.Username IS NULL
ORDER BY u.Username, c.CurriculumKey;

Many thanks!! That helps a lot.
Rob
Post #1366760
Posted Monday, October 01, 2012 3:12 PM
Old Hand

Old HandOld HandOld HandOld HandOld HandOld HandOld HandOld Hand

Group: General Forum Members
Last Login: Friday, June 14, 2013 3:11 PM
Points: 338, Visits: 993
You have an ORDER BY clause with a field from the joined table. Since ORDER BY can't evaluate null, I think this is making it an inner join.

I'd leave the ORDER BY off and let whatever application is receiving the data do the sorting.
Post #1366784
Posted Monday, October 01, 2012 5:32 PM
SSC Veteran

SSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC Veteran

Group: General Forum Members
Last Login: Friday, May 17, 2013 5:25 PM
Points: 269, Visits: 67
Here's another way:
select uc.UserName, uc.CurriculumKey  -- Select the user's...
from UserCurriculum uc
where exists ( -- ...where you can't find a missing Curriculum
select *
from Curriculum c1
left outer join
UserCurriculum uc1
on c1.CurriculumKey = uc1.CurriculumKey
and uc.UserName = uc1.Username
where
uc1.CurriculumKey is Null
)

Post #1366836
Posted Tuesday, October 02, 2012 8:37 AM
Right there with Babe

Right there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with Babe

Group: General Forum Members
Last Login: 2 days ago @ 6:44 AM
Points: 759, Visits: 802
dan-572483 (10/1/2012)
You have an ORDER BY clause with a field from the joined table. Since ORDER BY can't evaluate null, I think this is making it an inner join.


Dan, I'm not sure what you mean about the ORDER BY not evaluating Nulls -- ORDER BY doesn't change in any way the number of rows getting returned. Nulls just sort to the top.

ASC | DESC
Specifies that the values in the specified column should be sorted in ascending or descending order. ASC sorts from the lowest value to highest value. DESC sorts from highest value to lowest value. ASC is the default sort order. Null values are treated as the lowest possible values.


See: http://msdn.microsoft.com/en-us/library/ms188385.aspx

Post #1367077
« Prev Topic | Next Topic »

Add to briefcase 12»»

Permissions Expand / Collapse