提问人:Alexander Chereji 提问时间:8/24/2023 最后编辑:Alexander Chereji 更新时间:8/24/2023 访问量:59
如何在MySQL中对同一表的多列进行INNER JOIN
How to do a INNER JOIN on multiple columns of the same table in MySQL
问:
我有以下问题:我有三个表:日志、媒体和用户。
CREATE TABLE `users` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
ROW_FORMAT=DEFAULT;
CREATE TABLE `media` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`title` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
ROW_FORMAT=DEFAULT;
CREATE TABLE `log` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`action` VARCHAR(20) NOT NULL,
`action_time` DATETIME NOT NULL,
`user_id` INTEGER NOT NULL,
`affected_user_id` INTEGER DEFAULT NULL,
`media_id` INTEGER DEFAULT NULL,
`comment` TEXT DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
ROW_FORMAT=DEFAULT;
日志表的要点是,所做的每个操作都是由用户完成的,但有些操作会影响用户,有些操作会影响媒体,但并非总是如此。某些操作会影响用户和媒体。
列 user_id, affected_user_id 是要 users.id
的外键 列 media_id 是要 media.id 的外键
如果该列没有值,则该值为 NULL。
我想做的是对日志进行 SELECT 查询,并对其他两个表进行 INNER JOIN。
首先我尝试了这个查询,不知道有什么问题,所以这将是我第一次尝试做这样的事情:
SELECT log.action, log.action_time, log.user_id, user_name_table.name AS user_name,
log.affected_user_id, affected_user_name_table.name AS affected_user_name,
log.media_id, media.title AS media_title, log.comment
FROM log
INNER JOIN users AS user_name_table ON user_name_table.id = log.user_id
INNER JOIN users AS affected_user_name_table ON affected_user_name_table.id = log.affected_user_id
INNER JOIN media ON media.id = log.media_id
WHERE log.user_id=1 OR log.affected_user_id=1
我在互联网上查找了如何在两列上内部连接同一个表,我真的不知道它是否正确,也许这也是问题所在。我希望此查询将返回日志表的所有列以及与user_id和affected_user_id关联的用户的名称。
在日志表中,有足够多的行具有 user_id=1 或 affected_user_id=1。但不知何故,我的结果集是空的。我没有收到错误消息,所以我的查询语法应该没问题。
我还尝试了其他几个版本,例如:
SELECT log.action, log.action_time, log.user_id, users.name AS user_name, log.affected_user_id,
log.media_id, media.title AS media_title, log.comment
FROM log
INNER JOIN users ON users.id = log.user_id OR users.id=log.affected_user_id
INNER JOIN media ON media.id = log.media_id
WHERE log.user_id=1 OR log.affected_user_id=1
SELECT log.action, log.action_time, log.user_id, users.name AS user_name,
log.affected_user_id,
log.media_id, media.title AS media_title, log.comment
FROM log
INNER JOIN users ON users.id = log.user_id = affected_user_id
INNER JOIN media ON media.id = log.media_id
WHERE log.user_id=1 OR log.affected_user_id=1
我已经在互联网上搜索了解决方案,但我似乎没有找到。我什至问过 ChatGPT :),但它说我的查询完全没问题,应该返回我的结果集。
答:
0赞
Littlefoot
8/24/2023
#1
如果我理解正确,这会有所帮助吗?
SELECT log.action,
log.action_time,
log.user_id,
users.name AS user_name,
log.affected_user_id,
log.media_id,
media.title AS media_title,
log.comment
FROM log
INNER JOIN users
ON ( users.id = log.user_id
AND log.user_id = 1)
OR ( users.id = log.affected_user_id
AND log.affected_user_id = 1)
INNER JOIN media ON media.id = log.media_id
[编辑],在您发布示例数据后:
SQL> SELECT * FROM users;
ID NAME
---------- -----
1 Alex
2 Heinz
3 Frank
SQL> SELECT * FROM media;
ID TITLE
---------- ---------------
1 Harry Potter
2 Some other book
3 No idea
SQL> SELECT * FROM log;
ID ACTION ACTION_TIME USER_ID AFFECTED_USER_ID MEDIA_ID
---------- ------------ ------------------- ---------- ---------------- ----------
1 MEDIA_EDIT 2023-08-23 17:56:04 1 5
2 USER_EDIT 2023-08-23 17:56:04 1 3
3 MEDIA_BORROW 2023-08-23 17:56:04 1 3 1
查询,将表联接到表两次:一次为(内部联接),另一次为(外部联接)。log
users
log.user_id
log.affected_user_id
SQL> SELECT l.action,
2 l.action_time,
3 u.name AS user_name,
4 au.name AS affected_user_name,
5 m.title media_title
6 FROM LOG l
7 JOIN users u ON u.id = l.user_id
8 LEFT JOIN users au ON au.id = l.affected_user_id
9 LEFT JOIN media m ON m.id = l.media_id;
ACTION ACTION_TIME USER_NAME AFFECTED_USER_NAME MEDIA_TITLE
------------ ------------------- --------- ----------------------- ---------------
MEDIA_BORROW 2023-08-23 17:56:04 Alex Frank Harry Potter
USER_EDIT 2023-08-23 17:56:04 Alex Frank
MEDIA_EDIT 2023-08-23 17:56:04 Alex
SQL>
评论
0赞
Alexander Chereji
8/24/2023
我试过了,但似乎没有用。只是为了让我理解,INNER JOIN 和 WHERE 同时是吗?(users.id = log.user_id AND log.user_id = 1)
0赞
Littlefoot
8/24/2023
你理解正确。如果它不起作用,请考虑发布一些示例数据和所需的输出(基于此类数据) - 这可能会帮助我们(社区)帮助您
0赞
Alexander Chereji
8/24/2023
对于用户来说,这些结果集是可能的: 对于媒体,它将是这些: 对于日志,有几种可能性: 列注释并不重要,所以我把它设为 NULL(1, 'Alex')
(2, 'Heinz')
(3, 'Frank')
(1, 'Harry Potter')
(2, 'Some other book')
(3, 'no idea')
(1, 'MEDIA_EDIT', '2023-08-23 17:56:04', 1, Null, 5, Null)
(2, 'USER_EDIT', '2023-08-23 17:56:04', 1, 3, Null, Null)
(3, 'MEDIA_BORROW', '2023-08-23 17:56:04', 1, 3, 5, Null)
0赞
Littlefoot
8/24/2023
我编辑了答案;请看一看。
1赞
Alexander Chereji
8/24/2023
我试了几次,它似乎工作得很好。我将学习左连接和外部连接以完全理解您的查询,但非常感谢您,您真的在棘手的情况下帮助了我!
评论
LEFT JOIN
INNER
SELECT COUNT(*) FROM logs WHERE media_id IS NOT NULL AND user_id IS NOT NULL AND affected_user_id IS NOT NULL AND (user_id = 1 OR affected_user_id = 1)