T-SQL 选择连接 3 个表

Posted

技术标签:

【中文标题】T-SQL 选择连接 3 个表【英文标题】:T-SQL Select Join 3 Tables 【发布时间】:2017-09-18 04:21:44 【问题描述】:

我目前正在 SQL Server 2012 上的 T-SQL 中进行选择查询。这是一个复杂的查询,我想从 3 个表中查询一个列表。结果应如下所示:

所需的输出:

ProjectId |    Title    | Manager   | Contact   | StatusId 
----------+-------------+-----------+-----------+-----------
1         |   projectX  |   1123    |  4453     |  1 
2         |   projectY  |   2245    |  5567     |  1
3         |   projectZ  |   3335    |  8899     |  1

我的 3 张桌子: 1) 项目: ProjectId、ProjectDataId、MemberVersionId 2) ProjectData: ProjectDataId、Title、StatusId 3) 成员: MemberId、MemberVersionId、MemberTypeId、EmployeeId

棘手的部分是实现版本控制。因此,随着时间的推移,项目成员可以更改,并且应该始终可以返回到以前的版本,这就是为什么我使用 MemberVersionId 作为 Project 和 成员。表 Project 和 ProjectData 与 ProjectDataId 链接。

因此,1 个项目有 1 个 OfferData,1 个项目有 N 个成员。

一些示例数据:项目

ProjectId | ProjectDataId | MemberVersionId | 
----------+---------------+-----------------+
1         |   2           |   1             | 
2         |   3           |   1             |
3         |   4           |   1             |

项目数据

ProjectDataId |    Title    | StatusId 
--------------+-------------+-----------
2             |   projectX  |  1 
3             |   projectY  |  1
4             |   projectZ  |  1

成员: MemberTypeId 1 = 经理,MemberTypeId 2 = 联系人,3 = 其他

MemberId | MemberVersionId | MemberTypeId | EmployeeId | 
---------+-----------------+--------------+------------+
1        |   1             |   1          |  1123      | 
2        |   1             |   2          |  4453      |
3        |   1             |   3          |  9999      |
4        |   2             |   1          |  2245      | 
5        |   2             |   2          |  5567      | 
6        |   2             |   3          |  9999      | 
7        |   3             |   1          |  3335      | 
8        |   3             |   2          |  8899      | 
9        |   3             |   3          |  9999      | 

我当前的查询如下所示:

SELECT ProjectId, Title, EmployeeId AS Manager, EmployeeId AS Contact, StatusId
FROM [MySchema].[Project] a,
     [MySchema].[ProjectData] b,
     [MySchema].[Members] c
WHERE a.ProjectDataId = b.ProjectDataId
  AND a.MemberVersionId = c.MemberVersionId

不幸的是,这还不起作用。你知道如何解决这个问题吗?

谢谢

【问题讨论】:

添加所需的输出 今日提示:切换到现代、明确的JOIN 语法!更容易编写(没有错误),更容易阅读维护,如果需要更容易转换为外连接! 【参考方案1】:

这样的?

SELECT 
    p.ProjectId, 
    pd.Title, 
    mm.EmployeeId AS Manager, 
    mc.EmployeeId AS Contact, 
    pd.StatusId
FROM 
    [MySchema].[Project] p
    INNER JOIN [MySchema].[ProjectData] pd ON pd.ProjectDataId = p.ProjectDataId
    INNER JOIN [MySchema].[Members] mm ON mm.MemberVersionId = p.MemberVersionId AND mm.MemberTypeId = 1
    INNER JOIN [MySchema].[Members] mc ON mc.MemberVersionId = p.MemberVersionId AND mc.MemberTypeId = 2;

【讨论】:

最佳答案。易于阅读、正确的连接、适当的表别名。 完美运行!感谢您的帮助!【参考方案2】:

你可以试试这个:

    SELECT ProjectId, Title, C.EmployeeId AS Manager, d.EmployeeId AS Contact, StatusId
FROM [MySchema].[Project] a
INNER JOIN    [MySchema].[ProjectData] b ON A.ProjectDataId=B.ProjectDataId
LEFT JOIN (SELECT * FROM [MySchema].[Members] WHERE MemberTypeID=1) c ON a.MemberVersionId=c.MemberVersionId  
LEFT JOIN  (SELECT * FROM [MySchema].[Members] WHERE MemberTypeID=2)  d ON a.MemberVersionId=d.MemberVersionId 

【讨论】:

【参考方案3】:

您必须选择两次成员,一次用于经理,一次用于联系人:

SELECT ProjectId, Title, m.EmployeeId AS Manager, c.EmployeeId AS 
    Contact, StatusId
FROM [MySchema].[Project] a,
  [MySchema].[ProjectData] b,
  [MySchema].[Members] m
  [MySchema].[Members] c
WHERE a.ProjectDataId = b.ProjectDataId
  AND a.MemberVersionId = m.MemberVersionId and m.MemberTypeId = 1
  AND a.MemberVersionId = c.MemberVersionId and c.MemberTypeId = 2

【讨论】:

【参考方案4】:

试试这个,

 SELECT ProjectId, Title, cmanager.EmployeeId AS Manager, ccon.EmployeeId AS 
 Contact, StatusId
 from  [MySchema].[ProjectData] b
 inner join [MySchema].[Project] a on b.ProjectDataId=a.ProjectDataId
 left join [MySchema].[Members] cmanager on cmanager.MemberVersionId = 
  a.MemberVersionId and cmanager.MemberTypeId=1
 left join [MySchema].[Members] ccon on ccon.MemberVersionId = 
 a.MemberVersionId and ccon.MemberTypeId=2  

【讨论】:

【参考方案5】:

解决您的问题的最简单方法是将附加字段引入Project 表。您可以将其称为LatestMemberVersion(int,拥有当前最高的 MemberVersionId),这将是关系的最新版本,您可以添加更简单的IsLatestMemberVersion(位,如果记录为 1,则为最新的/活动的)。您可以使用ROW_NUMBER() OVER 语句计算它们。

然后,查询将变为:

SELECT ProjectId, Title, EmployeeId AS Manager, EmployeeId AS Contact, StatusId
FROM [MySchema].[Project] a,
     [MySchema].[ProjectData] b ON a.ProjectDataId = b.ProjectDataId
     [MySchema].[Members] c ON a.MemberVersionId = c.MemberVersionId
WHERE 
a.[IsLatestMemberVersion] = 1 -- alternative is a.[LatestMemberVersion] = a.[MemberVersionId]

此外,您还可以尝试两件事:

    您可能想从数据仓库中借用一些想法,即您希望将渐变维度类型 1 和 2 结合起来

    您可以尝试使用 SQL Server 功能,例如更改数据跟踪。但是我没有这方面的经验,所以它可能会一事无成。

最后一条建议,如果可以的话,永远不要将连接条件写入 WHERE 子句。它不可读,并且当您突然将 JOIN 更改为 LEFT JOIN 时可能会导致问题。 Microsoft 本身建议在适用时使用ON 而不是WHERE

【讨论】:

以上是关于T-SQL 选择连接 3 个表的主要内容,如果未能解决你的问题,请参考以下文章

用于从连接表中进行选择的 T-SQL 查询,其中有可变数量的参数?

SQL Server ---T-SQl基本语句

查询 - 从 3 个表连接

mysql中3个表的内连接

如何从内部连接的第二个表中按列选择前 1 个顺序 desc?

Oracle:将两个表与一个公共列加上第二个表中的一个附加列(最新生效日期)连接以选择其他列