Mysql查询查找下同订单的朋友和朋友的朋友

Posted

技术标签:

【中文标题】Mysql查询查找下同订单的朋友和朋友的朋友【英文标题】:Mysql Query to find friends and friends of friends who placed same order 【发布时间】:2016-09-14 20:38:24 【问题描述】:

我有如下 3 个表

用户

- id integer primary_key
- user_name 

朋友

- id autoincrement primary_key 
- user1 integer foreign_key(User.id)
- user2 integer foreign_key(User.id)

订单

- id integer primary_key autoincrement
- product_id integer 
- by_user foreign_key(User.id) 

我已经获得了用户的 id 和 product_id 。

我必须编写一个查询,该查询将为我提供该用户下订单相同产品的所有朋友以及该用户下订单相同产品的所有朋友。 p>

如何在 mysql 中编写这样的查询?


示例数据说明

用户

id    |   name
------------------
1     |   peter   
2     |   sam
3     |   xang
4     |   aisha
5     |   rita
6     |   mojo
7     |   raj
8     |   ben

朋友

(如果 id 为 1 和 2 的用户是朋友,则可以存储为 user1 = 1 和 user2 = 2 或 user1 = 2 和 user2 = 1 ,都表示用户之间的关系)

id          user1        user2 
---------------------------------------------
1      |     1       |     2      
2      |     2       |     3      
3      |     3       |     4      
4      |     4       |     2      
5      |     5       |     6      
6      |     6       |     8      
7      |     8       |     1   

订单

id         product_id           by_user 
-----------------------------------------------
1      |    100        |          2        
2      |    100        |          3       
3      |    100        |          4       
4      |    100        |          5       
5      |    100        |          7       
6      |    101        |          5       
7      |    102        |          6       
8      |    103        |          1          

所以提供的数据是:

用户 = 1 和产品 = 100

我们要做的:

id = 1 的用户的朋友是 [2,8](我们称之为 f1)

f1 中用户的朋友是 = [1,3,4,6](我们称之为 f2)

现在从订单表中给出用户 ID,该用户 ID 为 product_id = 100 并且用户 ID 在 f1+f2 中,即 [2,8,1,3,4,6]

所以这里的结果应该是:

[2,3,4]

【问题讨论】:

PLsql 还是mysql?还添加您尝试过的内容.. “朋友”中的“id”主键是荒谬的。该表的主键应该是两列 user1 和 user2。 @MikeNakis。 . .这并不荒谬。关系表通常具有合成主键。一个合理的替代方案是复合主键。这两种选择都不“荒谬”。 @GordonLinoff 它允许多次输入关系。它没有任何用处,只会带来麻烦。许多人这样做的事实并不意味着它不是荒谬的。很多人也在第一次使用前声明了自己的变量,并将其初始化为零。这同样聪明。 @MikeNakis。 . . unique 约束足以表达唯一性。一方面,我发现自动递增列中的信息非常有用,例如插入值的顺序。 【参考方案1】:
SELECT DISTINCT u.id, u.name
FROM
    Friends f1
    INNER JOIN Friends f2
    ON f1.user1 = f2.user1
    OR f1.user1 = f2.user2
    OR f1.user2 = f2.user1
    OR f1.user2 = f2.user2
    INNER JOIN Orders o
    ON (f1.user1 = o.by_user
    OR f1.user2 = o.by_user
    OR f2.user1 = o.by_user
    OR f2.user2 = o.by_user)
    AND o.product_id = 100
    INNER JOIN Users u
    ON o.by_user = u.id
WHERE   
    (f1.user1 = 1
    OR f1.user2 = 1)

此答案已更新以考虑朋友之友并为您添加解释。

查询 Friends 表中包含用户 1 的任何记录,这将为您提供用户 1 以及他们的直接朋友。 将 SELF JOIN 添加到 Friends 表,其中 user1 = user1, 2 to 2 1 to 2 2 to 1 的所有组合为 OR 以获得所有朋友的 Fiends 获取与您现在拥有的 4 个用户列的任意组合相关的所有订单,并通过 product_id = 100 限制结果 您现在有重复的结果,因此选择 DISTINCT 以获得每个用户 1 条记录。

【讨论】:

确定这将适用于我添加的示例数据并且可以给我想要的结果吗?因为测试这个东西需要一段时间。 您能否也为您的解决方案添加一个小解释,我不是专业人士,肯定会从中学到一些东西。比复制粘贴更好:)【参考方案2】:

这应该是不言自明的,但只是为了更清楚地说明:创建视图以一步一步解决问题,并使用 UNION 关键字加入不同程度的友谊。

DROP TABLE IF EXISTS Users;
CREATE TABLE Users (
    id INTEGER PRIMARY KEY,
    name NVARCHAR(50)
);

DROP TABLE IF EXISTS Friends;
CREATE TABLE Friends (
  user1 INTEGER,
  user2 INTEGER,
  FOREIGN KEY (user1) REFERENCES Users(id),
  FOREIGN KEY (user2) REFERENCES Users(id)
  );

DROP TABLE IF EXISTS Orders;
CREATE TABLE Orders (
  id INTEGER PRIMARY KEY,
  by_user INTEGER,
  FOREIGN KEY (by_user) REFERENCES Users(id) 
);

INSERT INTO Users (id,name) VALUES (1,"a"),(2,"b"),(3,"c"),(4,"d"),(5,"e"),(6,"f");

INSERT INTO Friends (user1,user2) VALUES (1,2),(2,1),(2,3),(3,2);

INSERT INTO Orders (id,by_user) VALUES(1,1);

DROP VIEW IF EXISTS FirstOrderFriends;
CREATE VIEW FirstOrderFriends AS
    SELECT DISTINCT Users.id AS id, f1.user2 AS friend1
        FROM Users 
            LEFT JOIN Friends AS f1 ON f1.user1 = Users.id;

DROP VIEW IF EXISTS SecondOrderFriends;
CREATE VIEW SecondOrderFriends AS
    SELECT DISTINCT Users.id AS id, f2.user2 AS friend2
        FROM Users 
            LEFT JOIN Friends AS f1 ON f1.user1 = Users.id  
            LEFT JOIN Friends As f2 ON f2.user1 = f1.user2;

DROP VIEW IF EXISTS FirstAndSecondOrderFriends;
CREATE VIEW FirstAndSecondOrderFriends AS
    SELECT DISTINCT * FROM (
            SELECT * FROM FirstOrderFriends
        UNION
            SELECT * FROM SecondOrderFriends
    );

SELECT * 
    FROM Users LEFT JOIN FirstAndSecondOrderFriends 
        ON Users.id = FirstAndSecondOrderFriends.id
    WHERE Users.id = 1;

我只是使用WHERE Users.id = 1; 加入ORDERS 表作为练习留给学生。

【讨论】:

以上是关于Mysql查询查找下同订单的朋友和朋友的朋友的主要内容,如果未能解决你的问题,请参考以下文章

开始和MySQL做朋友——初识MySQL

MySQL存储过程,处理多个游标和查询结果

如何向女朋友介绍MySQL索引

MySQL:如果用户未设置 dnd 或用户已设置 dnd,则布尔查询返回 true 给定 ID 必须是朋友

怎么在WPS表格中快速查找自己需要的信息

多对多(自相关)特定订单实体框架