#php #mysql #mysqli
#php #mysql #mysqli
Вопрос:
Я хочу сделать так, чтобы скрипт отображал количество совпадений значений у разных пользователей. Например, в таблице watched
у меня есть идентификатор моего основного пользователя (1) и названия просмотренных им фильмов, а также просмотренные фильмы несколькими другими пользователями:
---- ---------- ---------
| id | users_id | watched |
---- ---------- ---------
| 1 | 1 | movie1 |
---- ---------- ---------
| 2 | 1 | movie2 |
---- ---------- ---------
| 3 | 1 | movie3 |
---- ---------- ---------
| 4 | 2 | movie2 |
---- ---------- ---------
| 5 | 2 | movie1 |
---- ---------- ---------
| 6 | 3 | movie1 |
---- ---------- ---------
| 7 | 3 | movie5 |
---- ---------- ---------
| 8 | 3 | movie4 |
---- ---------- ---------
Ожидаемый результат:
my id = `1`;
matched with id `2` 2 times on titles `movie2`, `movie1`;
matched with id `3` 1 times on titles `movie1`;
Или если идентификатор основного пользователя 3
:
my id = `3`;
matched with id `1` 1 times on titles `movie1`;
matched with id `2` 1 times on titles `movie1`;
И так далее..
Я пытался сделать что-то вроде:
<?php
session_start();
$connect = mysqli_connect("127.0.0.1", "root", "root", "movie");
$query = mysqli_query($connect, "SELECT * FROM profile INNER JOIN users ON profile.users_id = users.id");
$id = $_SESSION['id'];
echo "my id: " . $id;
$movies = mysqli_query($connect, "SELECT * FROM watched WHERE users_id = '$id'");
$titles = array();
for ($i = 0;$i < $movies->num_rows;$i )
{
$result2 = $movies->fetch_assoc();
$watched = $result2['watched'];
$find = mysqli_query($connect, "SELECT * FROM watched WHERE watched = '$watched'");
for ($l = 0;$l < $find->num_rows;$l )
{
$found = $find->fetch_assoc();
if ($found['watched'] === $result2['watched'] and $found['users_id'] !== $id)
{
$titles[] = $found['watched'];
}
}
}
$count_titles = array();
foreach ($titles as $a)
{
@$count_titles[$a] ;
}
$matches = count($count_titles); //num of matches
for ($i = 0;$i < $query->num_rows;$i )
{
$result = $query->fetch_assoc();
?>
<div><?php
echo "matched with id " . $result['id'] . " ";
echo $matches . " times";
foreach (array_keys($count_titles) as $key)
{
echo " on titles " . $key;
}
?></div>
<?php
} ?>
Но он отображает только общее количество совпадений по всей таблице, а не для каждого пользователя в отдельности. Как мне заставить это работать, как описано выше?
три таблицы:
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');
Комментарии:
1. Вероятно, он отображает несколько строк для каждого пользователя, что ожидаемо, он не собирается каким-то волшебным образом группировать их (обычно это делается в PHP). Лучшее, что вы могли бы сделать в SQL, это, вероятно,
GROUP_CONCANT
, а затем сгруппировать по идентификатору пользователя.2. Где именно я должен это сделать? Не могли бы вы, пожалуйста, показать мне.?
3. Многое из этого не имеет смысла, например,
SELECT * FROM watched WHERE users_id = '$id'
Затем вы беретеwatched
значение полей из этого и делаете это с нимSELECT * FROM watched WHERE watched = '$watched'
, так что у вас уже есть то, что это возвращает в$watched ~ $result2;
4. да… Извините, я знаю. Я новичок в mysql / php. у вас есть лучший способ сделать это?
Ответ №1:
Этот запрос предоставит вам необработанные данные, которые вы хотите:
SELECT w1.users_id AS user1, w2.users_id AS user2, GROUP_CONCAT(w2.watched ORDER BY w2.watched) AS movies
FROM watched w1
JOIN watched w2 ON w2.watched = w1.watched AND w2.users_id != w1.users_id
GROUP BY user1, user2
Вывод (для вашего примера данных):
user1 user2 movies
1 2 movie1,movie2
1 3 movie1
2 1 movie1,movie2
2 3 movie1
3 1 movie1
3 2 movie1
Вы можете уточнить запрос по мере необходимости (например, добавить WHERE w1.users_id = 1
, чтобы выбрать только совпадения с пользователем 1, или JOIN
в свои таблицы users
и profile
(по одному разу для каждого идентификатора пользователя), чтобы получить имена пользователей и т.д.)
Чтобы получить желаемый результат, вам больше не нужны таблицы, вы можете просто использовать что-то вроде:
$id = $_SESSION['id'];
echo "my id: $idn";
$movies = mysqli_query($connect, "SELECT w1.users_id AS user1,
w2.users_id AS user2,
COUNT(w2.watched) AS num_movies,
GROUP_CONCAT(w2.watched ORDER BY w2.watched) AS movies
FROM watched w1
JOIN watched w2 ON w2.watched = w1.watched AND w2.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";
}
Комментарии:
1. Я думал, что мог бы объединить все таблицы (все 3) и сделать только один SQL для всего этого… но, увы, я не знаю, что представляют собой две другие таблицы
SELECT {other fields here} GROUP_CONCAT(w.watched) as watched FROM profile AS p JOIN users AS u ON p.users_id = u.id LEFT JOIN watched AS w ON w.users_id = u.id WHERE u.id = ? GROUP BY w.users_id
, Это все, что у меня есть.2. @ArtisticPhoenix полностью согласен (именно об этом был мой последний комментарий в ответе), но я не думал, что в вопросе достаточно данных, чтобы иметь возможность написать этот запрос
3. Я слишком ленив, чтобы выяснять больше…. лол… Я на собственном горьком опыте выяснил, что существует ограничение на то, как долго вы можете использовать групповое объединение… Хотя это довольно большой. Я использовал его для материализованного пути, и он усекал материал (таинственным образом) В принципе, у нас были некоторые данные иерархии вложенных наборов, но в некоторых случаях нам просто нужен был полный путь к этому узлу из корня, поэтому я использовал это, чтобы сократить время вычисления.
4. @valeria смотрите мою правку, вам действительно не нужны дополнительные таблицы, чтобы получить желаемый результат
5. @valeria взгляните на это, я начал играть с
JOIN
редактированиемusers
таблицы. Если этого недостаточно, то, я думаю, вам следует задать новый вопрос. db-fiddle.com/f/fU9ADMjY9mQ12rB1wVwU7F/5