将查找从1个表联接到多列

时间:2019-03-21 03:46:29

标签: sql sql-server

如何在不使用多个JOIN查询的情况下将1个表与另一个表中的多列链接? 以下是我的情况:

我有UserID的表Name

User
+---------+------------+
|      Id |       Name |
+---------+------------+
|       1 |       John |
|       2 |       Mike |
|       3 |    Charles |
+---------+------------+

Product有多列,但仅关注2列CreateByModifiedBy

+------------+-----------+-------------+
| product_id | CreateBy  | ModifiedBy  |
+------------+-----------+-------------+
|       1    | 1         | 3           |
|       2    | 1         | 3           |
|       3    | 2         | 3           |
|       4    | 2         | 1           |
|       5    | 2         | 3           |
+------------+-----------+-------------+

使用普通的JOIN,我将需要进行2次JOIN:

SELECT p.Product_id,
    u1.Name AS CreateByName,
    u2.Name AS ModifiedByName
FROM Product p
JOIN USER user u1 ON p.CreateBy = u1.Id,
JOIN USER user u2 ON p.ModifiedBy = u2.Id

得出结果

+------------+---------------+-----------------+
| product_id | CreateByName  | ModifiedByName  |
+------------+---------------+-----------------+
|       1    | John          | Charles         |
|       2    | John          | Charles         |
|       3    | Mike          | Charles         |
|       4    | Mike          | John            |
|       5    | Mike          | Charles         |
+------------+---------------+-----------------+

如何避免两次JOIN

我正在使用MS-SQL,但出于自己的好奇心向所有SQL查询开放

3 个答案:

答案 0 :(得分:1)

我认为您当前的设计/方法是可以接受的,并且需要两个联接是因为有两个用户ID列。两列中的每一列都需要一个单独的联接。

有趣的是,这是一个表设计,如果您真的只想执行一个联接,可以考虑使用它:

+------------+-----------+-------------+
| product_id | user_id   | type        |
+------------+-----------+-------------+
|       1    | 1         | created     |
|       2    | 1         | created     |
|       3    | 2         | created     |
|       4    | 2         | created     |
|       5    | 2         | created     |
|       1    | 3         | modified    |
|       2    | 3         | modified    |
|       3    | 3         | modified    |
|       4    | 1         | modified    |
|       5    | 3         | modified    |
+------------+-----------+-------------+

现在,您只需进行一个简单的联接,然后进行聚合:

SELECT
    p.product_id,
    MAX(CASE WHEN t.type = 'created'  THEN u.Name END) AS CreateByName,
    MAX(CASE WHEN t.type = 'modified' THEN u.Name END) AS ModifiedByName
FROM Product p
INNER JOIN user u
    ON p.user_id = u.Id
GROUP BY
    p.product_id;

请注意,我完全不推荐这种方法。使用当前的方法并使用两个联接要干净得多。使用一个或多个索引可以很容易地优化联接。上面的聚合方法可能无法达到您已有的效果。

答案 1 :(得分:1)

如果使用自然键而不是替代键,则完全不需要加入。 我不知道您如何将您的产品与现实世界区分开来,但是对于这个示例,我假设您拥有一个UPC

CREATE TABLE User 
(Name VARCHAR(20) PRIMARY KEY);
CREATE TABLE Product 
(UPC CHAR(12) PRIMARY KEY, 
CreatedBy VARCHAR(20) REFERENCES User(Name),
ModifiedBy VARCHAR(20) REFERENCES User(Name)
);

现在,您的查询是一个简单的选择,并且您还将用户名的唯一性作为奖励,并且不需要其他索引。 试试吧...

HTH

答案 2 :(得分:1)

加入是最好的方法,但是如果要寻找替代方法,则可以使用内联查询。

SELECT P.PRODUCT_ID,
       (SELECT [NAME] FROM @USER WHERE ID = CREATED_BY) AS CREATED_BY,
       (SELECT [NAME] FROM @USER WHERE ID = MODIFIED_BY) AS MODIFIED_BY
FROM @PRODUCT P

DEMO