仅显示某些表中没有的值。的MySQL

时间:2019-03-15 11:57:08

标签: php mysql

我有一个名为matches的表,用户可以在其中决定自己喜欢的人。例如:

+----+----------+----------+
| id | users_id | match_id |
+----+----------+----------+
| 1  | 1        | 2        |
| 2  | 1        | 3        |
| 3  | 2        | 1        |
| 4  | 3        | 2        |
+----+----------+----------+

如上所示,第一个用户选择了用户23,第二个用户选择了1,第三个用户选择了2。现在,第一用户和第二用户是相互的(demo in fiddle,适用于v5.5)。

...以及万一其他互联网中断了...

CREATE TABLE watched (
  `id` INTEGER,
  `users_id` INTEGER,
  `watched` VARCHAR(6)
);

INSERT INTO watched
  (`id`, `users_id`, `watched`)
VALUES
  ('1', '1', 'movie1'),
  ('2', '1', 'movie2'),
  ('3', '1', 'movie3'),
  ('4', '2', 'movie2'),
  ('5', '2', 'movie1'),
  ('6', '3', 'movie1'),
  ('7', '3', 'movie5'),
  ('8', '3', 'movie4');

  CREATE TABLE users (
  `id` INTEGER,
  `name` VARCHAR(355),
  `email` VARCHAR(355)
);

INSERT INTO users
  (`id`, `name`, `email`)
VALUES
  ('1', 'name1', 'email1@mail.com'),
  ('2', 'name2', 'email2@mail.com'),
  ('3', 'name3', 'email3@mail.com');

  CREATE TABLE profile (
  `id` INTEGER,
  `users_id` INTEGER,
  `about` VARCHAR(355)
);

INSERT INTO profile
  (`id`, `users_id`, `about`)
VALUES
  ('1', '1', 'something about me'),
  ('2', '2', 'something about me'),
  ('3', '3', 'something about me');

  CREATE TABLE matches (
  `id` INTEGER,
  `users_id` INTEGER,
  `match_id` VARCHAR(355)
);

INSERT INTO matches
  (`id`, `users_id`, `match_id`)
VALUES
  ('1', '1', '2'),
  ('2', '1', '3'),
  ('3', '2', '1'),
  ('4', '3', '2');

  SELECT u1.users_id as me,
       u2.users_id as matched,
       p.*, u.*
from matches u1
join matches u2 on u2.match_id = u1.users_id 
and u2.users_id = u1.match_id    
JOIN users u ON u.id=u1.match_id 
JOIN profile p ON p.users_id=u1.match_id 
where u1.users_id = 1
group by me, matched

现在,存在另一个查询,该查询显示用户与其他用户匹配的电影标题。例如,如果user1观看了名为movie1的电影,而另外user2也观看了movie1,则它将显示匹配电影的数量(num_movies),他们的标题以及其他信息,例如用户与该用户的电子邮件等(来自表usersprofile):

    $movies = mysqli_query($connect, 
    "
    SELECT w1.users_id user1
         , u.name 
         , p.*
         , u.*
         , w2.users_id user2
         , COUNT(w2.watched) num_movies
         , GROUP_CONCAT(w2.watched ORDER BY w2.watched) movies 
      FROM watched w1 
      JOIN watched w2 
        ON w2.watched = w1.watched 
       AND w2.users_id != w1.users_id 
      JOIN users u 
        ON u.id = w1.users_id 
      JOIN profile p 
        ON p.users_id = w1.users_id 
     WHERE w1.users_id = $id 
     GROUP 
        BY user1
         , user2
");

while ($row = $movies->fetch_assoc()) {
    echo "matched with id {$row['user2']} {$row['num_movies']} times on titles {$row['movies']}\n";
}

或参见demo

我想这样做,以便上面的查询将仅显示不相互的用户,即不在表matches中的用户。在我们的情况下,主要用户为user2,它应仅显示user3及其匹配的电影标题等。

我该怎么做?

我尝试添加类似 join matches m on m.users_id!=w2.users_id  或m.match_id in(select match_id from matches)!=w2.users_id,但这些似乎无效。

1 个答案:

答案 0 :(得分:1)

一种实现方法是

  • user表开始
  • 内部加入user_id上的watched
  • 再次加入user_id上的watched不同于当前用户,并且电影名称相同

通过这种方式,您可以获得每个用户和其他任何用户喜欢的所有电影。

剩下的是为每个用户过滤出共同的用户。为此,您可以:

  • 在user_id和match_id上左加入matches
  • 按用户1,用户2分组
  • 计算不重复的匹配ID
  • 当count = 2(共同的朋友)时过滤掉

以下是查询:

SELECT u.*, u.id as user1, w2.users_id as user2, count(DISTINCT m.id) AS matched, GROUP_CONCAT(DISTINCT w1.watched ORDER BY w1.watched) AS movies, COUNT(DISTINCT w1.id) AS num_movies
FROM users u
INNER JOIN watched w1 ON w1.users_id = u.id
INNER JOIN watched w2 ON (w1.users_id != w2.users_id) AND w2.watched = w1.watched
LEFT JOIN matches m ON (m.users_id = w1.users_id AND m.match_id = w2.users_id) OR (m.users_id = w2.users_id AND m.match_id = w1.users_id)
WHERE w1.users_id < w2.users_id
GROUP BY user1, user2
HAVING matched < 2

Example query