【问题标题】:When doing an OUTER JOIN to a table how can I join in another table to the one on the Right of the outer Join?在对表执行 OUTER JOIN 时,如何将另一个表加入到外部联接右侧的表中?
【发布时间】:2014-10-18 14:25:33
【问题描述】:

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

我有四张桌子:

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

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

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

【问题讨论】:

  • 能否提供表格的示例数据

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


【解决方案1】:

只有在有 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 

【讨论】:

  • AdminTest 是否有 UserId 列?
  • @SamanthaJ 感谢您的更新。可以清楚地分别提及您的输入、当前输出和所需输出。确保为输入添加表名。
  • 感谢您的更新,请添加 AdminTestQuestion 和 UserTestStatus 表数据,并确保在数据中查询中使用的所有列,例如用户测试表中缺少购买日期
  • 我明白是什么导致当前输出更新代码
  • 谢谢 - 这工作!我对 group by 做了一个小改动。做得好。我现在接受:-)
猜你喜欢
  • 2016-12-07
  • 2017-07-26
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-28
相关资源
最近更新 更多