在对表进行OUTER JOIN时,如何将另一个表连接到外部Join的右侧?

时间:2014-10-18 14:25:34

标签: sql sql-server sql-server-2012

我有一个ASP.Net Sql Server 2012应用程序,我正在尝试使用SQL从四个表创建一个报告。我在获取一个字段(状态)字段的数据时遇到问题。

我有四张桌子:

  • AdminTest - 可用的测试
  • AdminTestQuestions - 测试题
  • UserTest - 测试用户已购买
  • UserTestStatus - 一个参考表(包含两列:UserTestStatusId和Name)

我想要做的是创建一个这样的报告,它显示了在AdminTest和UserTest表中有一个antry的测试ABC和只在AdminTest表中有一个条目的测试DEF:

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

最初只有AdminTest行,没有可用于加入的UserTest。使用LEFT OUTER JOIN可以正常处理。当用户购买测试时,购买日期将有一个条目,我将能够加入UserTest和UserTestStatus列。

如果没有用户测试,那么我希望状态设置为“立即购买”

这是我到目前为止所拥有的。它仅适用于特定测试代码的AdminTest和UserTest表。

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

所以连接需要看起来像这样:

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

有人可以给我一些建议,告诉我如何让状态的数据等于单词“Purchase Now”,或者如果有UserTest那么就是实际状态已被购买。

更新:

这是一个提出的答案。我包括了这个以及下面三个选项的输出。我希望这有助于显示数据。我可以在这里添加任何其他内容,以便在需要时显示更多数据。

选择1:

SELECT Code, AdminTestId 
FROM AdminTest

输出

Code    AdminTestId
abcdef  131
ddddddd 1130

选择2:

SELECT AdminTestId, UserTestId 
FROM UserTest

输出

AdminTestId UserTestId
131           202

选择3:

SELECT AdminTestQuestionId, AdmintestId, QuestionUId
FROM AdminTestQuestion

输出

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

选择4:

SELECT * 
FROM UserTestStatus

输出:

0   Available
1   Started
2   Paused
3   Finished
4   Marked

解决方案:

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

以下是我需要看到的内容:

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

1 个答案:

答案 0 :(得分:4)

  

仅当有一个AdminTest和UserTest表时,它才有效   特别测试代码。

发生这种情况的原因是因为您的加入条件UserTest.UserId = @UserId限制了结果在UserTest中有UserId的连接发生。这需要更改为AdminTest.UserId = @UserId。在这里,我假设您将UserId存储在AdminTest中,UserTest只有用户购买的条目

  

如果没有用户测试,那么我希望设置状态   “立即购买”

为此,您需要使用CASE声明

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

更新 :(基于OP对问题的更新)

原始查询中的另一个错误是使用导致当前输出的GROUP BY PurchaseDateUserTestStatus

因此,您的最终查询将是

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