如何连接多个表?

Posted

技术标签:

【中文标题】如何连接多个表?【英文标题】:How do I join multible tables? 【发布时间】:2009-03-28 19:10:08 【问题描述】:

我有以下表格(和示例值):

**user:**
user_id (1, 2, 3)
username (john33, reddiamond...)
password (pass1, pass2...)

**session:**
session_id (4,5, 6)
user_id (1, 2, 3)

**activity**
activity_id (1, 2)
name (running, walking...)

**user_activity**
user_activity_id (1, 2, 3, 4, 5)
session_id (4, 5)
activity_id (1, 2)

所有同名的列都是相关的。在user_activity 表中,有几行描述了会话的活动以及活动指的是用户。

但是我想获取描述用户当前正在做什么的表格:

**result**
username(john33)
activity.name(walking)

获取结果表的SQL语句是什么?

(我正在使用 MSSQL)。

【问题讨论】:

【参考方案1】:
SELECT u.username, a.name
FROM user_activity ua
INNER JOIN session s
ON ua.session_id = s.session_id
INNER JOIN user u
ON s.user_id = u.user_id
INNER JOIN activity a
ON ua.activity_id = a.activity_id

【讨论】:

请注意,如果您有多个 user_activity 或 session 记录,那么这将返回所有记录,而不是当前记录,但当前已定义【参考方案2】:

我假设 session.session_iduser_activity.user_activity_idIDENTITY 列,所以它们是单调递增的。因此它们是唯一的,最大值表示最近的条目。

所以你需要做的是:

usersession 中具有最大session_id 值的对应行匹配(即,找不到具有相同user_id 和更大session_id 的其他行)。

然后将session 中的那一行匹配到user_activity 中具有最大user_activity_id 的对应行。

然后将user_activity 中的那一行与activity 中的对应行进行匹配,得到name

这是一个应该实现这一点的查询(虽然我还没有测试过):

SELECT u.username, a.name
FROM user u
 JOIN session s1 ON (u.user_id = s1.user_id)
 LEFT OUTER JOIN session s2 ON (u.user_id = s2.user_id 
   AND s1.session_id < s2.session_id)
 JOIN user_activity ua1 ON (ua1.session_id = s1.session_id)
 LEFT OUTER JOIN user_activity ua2 ON (ua2.session_id = s1.session_id 
   AND ua1.user_activity_id < ua2.user_activity_id)
 JOIN activity a ON (a.activity_id = ua1.activity_id)
WHERE s2.session_id IS NULL AND ua2.user_activity_id IS NULL;

这是另一种查询形式,应该得到相同的结果,并且可能更容易可视化:

SELECT u.username, a.name
FROM user u
 JOIN session s1 ON (u.user_id = s1.user_id)
 JOIN user_activity ua1 ON (ua1.session_id = s1.session_id)
 JOIN activity a ON (a.activity_id = ua1.activity_id)
WHERE s1.session_id = (
     SELECT MAX(s2.session_id) FROM session s2 
     WHERE s2.user_id = u.user_id)
 AND ua1.user_activity_id = (
     SELECT MAX(ua2.user_activity_id) FROM user_activity ua2 
     WHERE ua2.session_id = s1.session_id);

【讨论】:

+1 为什么需要选择 max(session_id) 不会让最大的 user_activity 记录起作用) @Steve:当然,把逻辑带入问题。 ;-)【参考方案3】:

我从您对期望结果的陈述中假设您希望找到每个用户的当前活动。我还假设一个用户可能有很多会话,并且当前会话是具有最高 session_id 的会话。

当然,如果您每个用户只有一个会话,每个用户只有一个 user_activity 记录,那么这不是问题,您接受的答案很好。

这里的关键问题是识别每个用户的最新 user_activity 记录并使用它来访问活动。

这可以通过以下方式完成:-

SELECT  u.username,  
        a.name  
FROM    user_activity AS ua  
JOIN    session AS s ON ua.session_id = s.session_id  
JOIN    user AS u ON u.user_id = s.user_id  
JOIN    activity AS a ON ua.activity_id = a.activity_id  
WHERE   ua.user_activity_id IN (  
          SELECT  MAX(ua2.user_activity_id)  
          FROM    user_activity AS ua2  
          JOIN    session AS s2 ON ua2.session_id = s2.session_id  
          GROUP BY s2.user_id);  

以下测试数据证明了 SQL。它创建 4 个用户和 4 个活动,然后为每个做家务的用户创建一个 user_activity 记录。然后它将三个用户设置为正常活动。

INSERT INTO user (username) VALUES ('sneezy');  
INSERT INTO user (username) VALUES ('grumpy');  
INSERT INTO user (username) VALUES ('happy');  
INSERT INTO user (username) VALUES ('snow_white');  

INSERT INTO session (user_id) SELECT u.user_id FROM user AS u;  

INSERT INTO activity(name) VALUES ("Sneezing");  
INSERT INTO activity(name) VALUES ("Frowning");  
INSERT INTO activity(name) VALUES ("Smiling");  
INSERT INTO activity(name) VALUES ("Housework");  

INSERT INTO user_activity (session_id, activity_id)  
SELECT s.session_id, a.activity_id  
FROM   session AS s JOIN activity AS a  
WHERE   a.name IN ("Housework");  

INSERT INTO user_activity(session_id, activity_id)  
SELECT  s.session_id, a.activity_id  
FROM    session AS s  
JOIN    USER as u ON s.user_id = u.user_id  
JOIN    activity AS a ON a.name = 'Sneezing'  
WHERE   u.username = 'sneezy' ;  

INSERT INTO user_activity(session_id, activity_id)  
SELECT  s.session_id, a.activity_id  
FROM    session AS s  
JOIN    USER as u ON s.user_id = u.user_id  
JOIN    activity AS a ON a.name = 'Frowning'  
WHERE   u.username = 'grumpy' ;  

INSERT INTO user_activity(session_id, activity_id)  
SELECT  s.session_id, a.activity_id  
FROM    session AS s  
JOIN    USER as u ON s.user_id = u.user_id  
JOIN    activity AS a ON a.name = 'Smiling'  
WHERE   u.username = 'happy' ;  

这会产生以下结果

snow_white 家务 打喷嚏打喷嚏 脾气暴躁的皱着眉头 快乐微笑

【讨论】:

【参考方案4】:

我认为会是这样的:

select u.username, a.name
from user u
join session s on u.user_id = s.user_id
join user_activity ua on ua.session_id = s.session_id
join activity a on a.activity_id = ua.activity_id

【讨论】:

【参考方案5】:
SELECT user.user_name,
activity.name1
FROM activity 

INNER JOIN user 
INNER JOIN session 
  ON user.user_id = session.user_id

INNER JOIN user_activity 
  ON session.session_id = user_activity.session_id 
  ON activity.activity_id = user_activity.activity_id

【讨论】:

以上是关于如何连接多个表?的主要内容,如果未能解决你的问题,请参考以下文章

如何连接多个表?

如何在连接多个表时使用 GROUP BY 连接字符串?

如何在同一张表上进行多个连接,然后与另一个表连接?

连接多个表后如何从sql查询结果中删除重复记录

通过多个分组连接多个表

sqlalchemy:如何通过一个查询连接多个表?