When doing OUTER JOIN to a table, how can I join the other table to the one on the right side of the outer join?

I have an ASP.NET Sql Server 2012 application and I am trying to create a report from four tables with SQL. I have a problem getting data for one field (status).

I have four tables:

  • AdminTest - available tests
  • AdminTestQuestions - Test Questions
  • UserTest - Checks what the user has purchased
  • UserTestStatus is a lookup table (with two columns: UserTestStatusId and name)

What I would like to do is create a report like this which shows an example ABC test that has antry in the AdminTest and UserTest tables, and a test DEF that only has an entry in the AdminTest table:

Code PurchaseDate  Questions Status
ABC  2012/1/1      50        Available
DEF                25        Purchase Now  

      

Initially there would be only AdminTest lines and no access to UserTest. This is ok with LEFT OUTER JOIN. When a user buys a test, there will be an entry on the day of purchase and I can join the UserTest and UserTestStatus columns.

If there is no custom test, I would like the status to be "Buy now"

Here's what I have so far. It only works if there is an AdminTest and UserTest table for the specific test code.

SELECT   AdminTest.Code        AS Code,     
         UserTest.PurchaseDate AS PurchaseDate,
         COUNT(AdminTestQuestion.AdminTestQuestionId) AS Questions,
         UserTestStatus.Name   AS Status
FROM     AdminTest LEFT OUTER JOIN UserTest ON  AdminTest.AdminTestId = UserTest.AdminTestId 
                                            AND UserTest.UserId = @UserId
JOIN     AdminTestQuestion ON  AdminTest.AdminTestId = AdminTestQuestion.AdminTestId
                           AND AdminTest.ExamId = @ExamId
                           AND AdminTest.TestStatusId = 3
JOIN     UserTestStatus    ON  UserTest.TestStatusId = UserTestStatus.UserTestStatusId 
GROUP BY AdminTest.Code,
     UserTest.PurchaseDate, 
     UserTestStatus.Name

      

So the connections should look like this:

AdminTest >>> AdminTestQuestions
          >>> UserTest (optional) >>> UserTestStatus 

      

Can anyone give me some advice as to how I can get the status data equal to the words " Purchase Now

" or be the actual status if purchased UserTest

.

Update:

Here is the answer that was suggested. I've included this as well as the output of the three selected below. Hope this helps to show the data. I can add something else to show more data if needed.

Select 1:

SELECT Code, AdminTestId 
FROM AdminTest

      

Output

Code    AdminTestId
abcdef  131
ddddddd 1130

      

Select 2:

SELECT AdminTestId, UserTestId 
FROM UserTest

      

Output

AdminTestId UserTestId
131           202

      

Choose 3:

SELECT AdminTestQuestionId, AdmintestId, QuestionUId
FROM AdminTestQuestion

      

Output

3094    131     3CEFF956-BF61-419E-8FB2-9D6A1B75B909
4094    1130    5D679FAD-2904-45A1-AA5F-3DB16850438D
4095    1130    96EA8351-FA2B-4DB3-862D-260CA085563A

      

Select 4:

SELECT * 
FROM UserTestStatus

      

Output:

0   Available
1   Started
2   Paused
3   Finished
4   Marked

      

Decision:

SELECT   temp.Code,     
         temp.Questions,
         UserTest.PurchaseDate AS PurchaseDate,
         (CASE 
              WHEN UserTestStatus.Name  IS NULL THEN 'Purchase Now'
              ELSE UserTestStatus.Name
         END)  AS Status
FROM
(SELECT   AdminTest.Code        AS Code,  
          AdminTest.AdminTestId,   
          COUNT(AdminTestQuestion.AdminTestQuestionId) AS Questions
 FROM     AdminTest 
 JOIN     AdminTestQuestion ON  AdminTest.AdminTestId = AdminTestQuestion.AdminTestId
                           AND AdminTest.TestStatusId = 3
 GROUP BY AdminTest.Code, AdminTest.AdminTestId) temp
LEFT OUTER JOIN UserTest       ON  temp.AdminTestId = UserTest.AdminTestId 
LEFT OUTER JOIN UserTestStatus ON  UserTest.TestStatusId = UserTestStatus.UserTestStatusId

      

Here's what I need to see:

Code    PurchaseDate            Questions Status
abcdef  2014-10-17 15:27:31.760    1      Available
ddddddd null                       1     Purchase Now

      

+3


source to share


1 answer


It only works if there is an AdminTest and UserTest table for the specific test code.

The reason for this is because your join condition UserTest.UserId = @UserId

limits the results to have UserId

in the UserTest in order for the join to happen. This needs to be changed to AdminTest.UserId = @UserId

. Here I am assuming you are saving UserId

in AdminTest

too, since UserTest

there are only records in there when a user buys

If there is no custom test, I would like the status to be "Buy now"

To do this, you need to use the CASE statement

     CASE 
          WHEN UserTestStatus.Name  IS NULL THEN 'Purchase Now'
          ELSE UserTestStatus.Name
     END

      



UPDATE : (based on OP updates for questions)

Another wrong original query was using GROUP BY

PurchaseDate

and UserTestStatus

, which is causing the current output.

So the final request would be

SELECT   temp.Code,     
         temp.Questions,
         UserTest.PurchaseDate AS PurchaseDate,
         (CASE 
              WHEN UserTestStatus.Name  IS NULL THEN 'Purchase Now'
              ELSE UserTestStatus.Name
         END)  AS Status
FROM
(SELECT   AdminTest.Code        AS Code,  
          AdminTest.AdminTestId,   
          COUNT(AdminTestQuestion.AdminTestQuestionId) AS Questions,
 FROM     AdminTest 
 JOIN     AdminTestQuestion ON  AdminTest.AdminTestId = AdminTestQuestion.AdminTestId
                           AND AdminTest.TestStatusId = 3
 GROUP BY AdminTest.Code) temp
LEFT OUTER JOIN UserTest       ON  temp.AdminTestId = UserTest.AdminTestId 
LEFT OUTER JOIN UserTestStatus ON  UserTest.TestStatusId = UserTestStatus.UserTestStatusId 

      

+4


source







All Articles