使用多列/键的 MySQL JOIN 3 表

标签 mysql sql join key multiple-tables

mySQL 的完全新手。所以任何帮助将不胜感激。

我有 3 个表 -- cartsusersactions

carts:
+------------+-------------+-------+
| cartId     | session_id  | userId| 
+------------+-------------+-------+

users:
+----------+-------------+
| usedId   | email       |
+----------+-------------+

actions:
+-------------+------------------+---- ---------+
| session_id  | impressionAction | impressionId | 
+-------------+------------------+-----+--------+

carts中,每一行有一个session_id

users中,每一行有一个userId

actions 中,每个 session_id 有多行,用于计算该 session 的所有操作。

我想JOIN三个表得到类似的输出

+------+-------------+--------+------------------+--------------+-------+
userId | session_id  | cartId | impressionAction | impressionId | email |
+------+-------------+--------+------------------+--------------+-------+

每个 userIdsession_id 有多行;本质上是一个扁平化的文件。我认为如果我们在 userIdJOIN cartsusers 导致说 A 和然后 JOIN Aactions' onsession_id`,我们到家了。

样本预期输出是:

+------------+-------------+--------+------------------+--------------+---------+
userId       | session_id  | cartId | impressionAction | impressionId | email   |
+------------+-------------+--------+------------------+--------------+---------+
| 1234       | abc3f45     | 0001   | LOGIN            | 2032         |ab@yc.com|
| 1234       | abc3f45     | 0001   | ADD              | 4372         |ab@yc.com|
| 1234       | abc3f45     | 0001   | ADD              | 4372         |ab@yc.com|
| 1234       | abc3f45     | 0001   | SENDMAIL         | ab@yc.com    |ab@yw.com| 
| 4567       | def4rg4     | 0002   | LOGIN            | 2032         |db@yw.com|
| 4567       | def4rg4     | 0002   | ADD              | 4372         |db@yw.com|
| 4567       | def4rg4     | 0002   | REMOVE           | 3210         |db@yw.com|
+------------+-------------+--------+------------------+--------------+---------+** 

我不知道如何在没有一个公共(public)键的情况下连接 3 个表。我什至不知道它叫什么类型的连接。

本质上,我们试图连接 3 个具有非重叠键的表,通过第一个 JOIN 收集一个公共(public)键,然后将中间键与第三个连接。这称为 CROSS JOIN 吗?如果没有,有名字吗?

最佳答案

摘自你上面的评论

A USER may select many products, add them to their CART; a single USER may have multiple CARTS and at the end of the event, they can EMAIL the cart to themselves; the ACTIONS of the user are stored in the actions table

这就是我对结构的看法(考虑到您的数据)

+---------------------+     +---------------------+     +---------------------+
| users               |     | carts               |     | actions             |
+---------------------+     +---------------------+     +---------------------+
| user_id       [PK]  |--|  | cart_id       [PK]  |     | impression_id [PK]  |
| email               |  |--| user_id       [FK]  |     | action_name         |
|                     |     | product_id    [FK]  |  |--| session_id    [FK]* |
+---------------------+     | session_id    [FK]* |--|  |                     |
                            |                     |     +---------------------+
                            +---------------------+    

正如您在上面看到的,我首先加入购物车,然后加入操作,因为只有桌面购物车同时具有用户和 session 数据。

购物车和操作上 session_id 旁边的 [FK]* 可能看起来是外键,但在这种情况下它不是 - 因为没有单独的 session 表将其放置为PK(主键)

您询问了join - 它与inner join 相同。 INNER JOIN 通过基于连接谓词组合两个表(A 和 B)的列值来创建一个新的结果表。该查询将 A 的每一行与 B 的每一行进行比较,以找到满足连接谓词的所有行对。

这是一个可能的表格内容

+------------------------+
| users                  |
+------------------------+
| id   | email           |
+------+-----------------+
| 1    | first@mail.org  |
| 2    | second@mail.org |
| 3    | third@mail.org  |
+------+-----------------+

+------------------------------------------+
| carts                                    |
+------------------------------------------+
| id   | user_id | product_id | session_id |
+------+---------+------------+------------+
| 1    | 1       | 5          | 1aaaa      |
| 2    | 2       | 5          | 2ffff      |
| 3    | 3       | 8          | 3ddddd     |
| 4    | 1       | 5          | 1aaaaa     |
| 5    | 3       | 9          | 3bbbbb     |
| 6    | 1       | 6          | 1ccccc     |
+------+---------+------------+------------+

+-------------------------------+
| actions                       |
+-------------------------------+
| id   | name      | session_id |
+------+-----------+------------+
|  1   | ADD       | 1aaaa      |
|  2   | ADD       | 2ffff      |
|  3   | SENDMAIL  | 3ddddd     |
|  4   | ADD       | 3ddddd     |
|  5   | SENDMAIL  | 2ffff      |
|  6   | ADD       | 1aaaaa     |
|  7   | REMOVE    | 3ddddd     |
|  8   | ADD       | 1ccccc     |
|  9   | ADD       | 3bbbbb     |
| 10   | SENDMAIL  | 3bbbbb     |
+------+-----------+------------+

如您所见,表格购物车中有六个产品,表格操作中正好有六个 add 操作。此外,正如您所见,id=1 的用户购买了三种产品,但不是同时购买,因为有两个 session ; id=3 的用户也在不同时间购买了这两种产品等等...

SQL语句

SELECT u.user_id, c.session_id, c.cart_id, a.impression_id, a.action_name, u.email
FROM users AS u
INNER JOIN carts AS c ON c.user_id = u.user_id
INNER JOIN actions AS a ON a.session_id = c.session_id
ORDER BY u.user_id, c.session_id, c.cart_id

结果:

+---------+------------+---------+---------------+-------------+-----------------+
| user_id | session_id | cart_id | impression_id | action_name | email           |
+---------+------------+---------+---------------+-------------+-----------------+
| 1       | 1aaaa      | 1       | 1             | ADD         | first@mail.org  |
| 1       | 1aaaa      | 1       | 6             | ADD         | first@mail.org  |
| 1       | 1aaaa      | 4       | 1             | ADD         | first@mail.org  |
| 1       | 1aaaa      | 4       | 6             | ADD         | first@mail.org  |
| 1       | 1cccc      | 6       | 8             | ADD         | first@mail.org  |
| 2       | 2ffff      | 2       | 5             | SENDMAIL    | second@mail.org |
| 2       | 2ffff      | 2       | 2             | ADD         | second@mail.org |
| 3       | 3bbbb      | 5       | 9             | ADD         | third@mail.org  |
| 3       | 3bbbb      | 5       | 10            | SENDMAIL    | third@mail.org  |
| 3       | 3dddd      | 3       | 3             | SENDMAIL    | third@mail.org  |
| 3       | 3dddd      | 3       | 4             | ADD         | third@mail.org  |
| 3       | 3dddd      | 3       | 7             | REMOVE      | third@mail.org  |
+---------+------------+---------+---------------+-------------+-----------------+

注意:不保证 session 的唯一性。

(更新)工作 SQL Fiddle


更新:(查找和删除重复项)

我已经更新了 SQL Fiddle为了模拟重复记录(当用户在同一 session 中添加相同的产品时)。使用以下语句,您将能够检索那些重复的行。

SELECT c.card_id, c.user_id, c.product_id, c.session_id, a.action_name, a.impression_id
FROM cards As c
INNER JOIN actions AS a ON a.session_id = c.session_id
GROUP BY c.user_id, c.product_id, c.session_id, a.action_name
HAVING count(*) > 1

结果:

+---------+------------+------------+------------+-------------+-----------------+
| card_id | user_id    | product_id | session_id | action_name | impression_id   |
+---------+------------+------------+------------+-------------+-----------------+
| 1       | 1          | 5          | 1aaaa      | ADD         | 1               |
| 6       | 1          | 6          | 1cccc      | ADD         | 8               |
+---------+------------+------------+------------+-------------+-----------------+

在上述语句的 SELECT 部分中,您可以省略除 card_id 和 impression_id 之外的所有内容。在一个语句中删除这两个重复项有点棘手,因为您不能修改在同一查询的子查询中选择的同一个表。在这种情况下,我会避免棘手的部分(涉及另一个内部子查询),并会使用如下单独的语句删除重复项

-- delete duplicates from cards
--
DELETE FROM WHERE card_id IN (1,6)

-- delete duplicates from actions
--
DELETE FROM WHERE card_id IN (1,8)

更好的是,您可以检查用户是否已经添加了所选产品并且不要添加两次。

关于使用多列/键的 MySQL JOIN 3 表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24639504/

相关文章:

mysql - 如何在子查询中使用 Count?

mysql - 为每个 ID 选择最大日期

java - 从 java 更新 Blob 时出现 SQL 语法错误

mysql - sql 选择重复项和单个项

sql - 选择数据库中的所有行,但仅选择最新(最高)版本

sql - 在 H2 中将特殊字符串转换为日期

Mysql查询5张表

php - mysql 显示数组 php 中的所有列名

python - 使用脚本填充 Sql 表

sql - Crystal 报告;图表专家 : creating a chart with two date ranges in X axis