|
|
|
Right 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
|
|
|
|
|
SSCoach
         
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
|
|
|
|
|
Right 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.
|
|
|
|
|
SSCoach
         
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
|
|
|
|
|
Right 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.
|
|
|
|
|
SSCoach
         
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
|
|
|
|
|
Right 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
|
|
|
|
|
Old 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.
|
|
|
|
|
SSC 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 )
|
|
|
|
|
Right 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
|
|
|
|