Как мне объединить несколько таблиц? - PullRequest
3 голосов
/ 28 марта 2009

У меня есть следующие таблицы (и примеры значений):

**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).

Ответы [ 5 ]

7 голосов
/ 28 марта 2009
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
2 голосов
/ 29 марта 2009

Я предполагаю из вашего заявления о желаемом результате, что вы хотите найти текущую активность каждого пользователя. Я также предполагаю, что у пользователя может быть много сеансов и текущий сеанс имеет самый высокий идентификатор сеанса.

Конечно, если у вас есть только один сеанс на пользователя и одна запись 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 Housework
  sneezy     Sneezing
  grumpy     Frowning
  happy      Smiling
2 голосов
/ 28 марта 2009

Полагаю, session.session_id и user_activity.user_activity_id - это столбцы IDENTITY, поэтому они монотонно растут. Поэтому они уникальны, и наибольшее значение указывает на самую последнюю запись.

Итак, что вам нужно сделать, это:

  • Сопоставьте user с соответствующей строкой в ​​session с наибольшим значением 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 голос
/ 28 марта 2009

Я думаю, это будет что-то вроде:

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
0 голосов
/ 24 февраля 2012
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...