3

I have three simple tables: users, profile and watched, which contains users' id and their watched movie titles.

and the script below displays the matched values with different users from the table watched:

$id = $_SESSION['id'];
echo "my id: $id\n";

$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";
}

output:

my id = `1`;
matched with id `2` 2 times on titles `movie2`, `movie1`;
matched with id `3` 1 times on titles `movie1`;

demo on fiddle

BUT I want to also display the users' names, profiles and so on. like in this query: SELECT * FROM profile INNER JOIN users ON profile.users_id = users.id

how can I merge the first and the second queries?

tried:

SELECT *, w2.watched, 
COUNT(w2.watched) AS num_movies, 
GROUP_CONCAT(w2.watched order by w2.watched) as movies

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 and w.watched=w2.watched
     WHERE u.id != $id
     GROUP BY w.users_id

but it's not working.

Dharman
  • 30,962
  • 25
  • 85
  • 135
dwin812
  • 133
  • 10
  • 1
    *"it's not working"* is no error description. Actual result, expected result, error messages? – Pinke Helga Mar 07 '19 at 02:39
  • 1
    Do you need to display both users' names and profiles, or just the other user? The first user is the user themself. – Barmar Mar 07 '19 at 02:48
  • 2
    `WHERE w1.users_id = $id` Use **prepared statements!** Read [How can I prevent SQL injection in PHP?](https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php/60496#60496) Don't rely on `$id = $_SESSION['id'];` always would stay safe. – Pinke Helga Mar 07 '19 at 02:57

3 Answers3

1

To fetch the raw data you want, you just need to JOIN the users and profile tables to the existing query, once for each user:

SELECT w1.users_id AS id1,
       u1.name AS user1,
       u1.email AS user1_email,
       p1.about AS user1_about,
       w2.users_id AS id2,
       u2.name AS user2,
       u2.email AS user2_email,
       p2.about AS user2_about,
       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
JOIN users u1 ON u1.id = w1.users_id
JOIN profile p1 ON p1.users_id = u1.id
JOIN users u2 ON u2.id = w2.users_id
JOIN profile p2 ON p2.users_id = u2.id
WHERE w1.users_id = 1
GROUP BY id1, user1, user1_email, user1_about, id2, user2, user2_email, user2_about

Output:

id1 user1   user1_email     user1_about         id2 user2   user2_email     user2_about         num_movies  movies
1   name1   email1@mail.com something about me  2   name2   email2@mail.com something about me  2           movie1,movie2
1   name1   email1@mail.com something about me  3   name3   email3@mail.com something about me  1           movie1

Demo on dbfiddle

In PHP you might then do something like:

$id = $_SESSION['id'];
$first = true;
$movies = mysqli_query($connect, "... the query above ...");
while ($row = $movies->fetch_assoc()) {
    if ($first) {
        echo "User {$row['user1']} ({$row['user1_email']}, {$row['user1_about']}):\n";
        $first = false;
    }
    echo "matched with {$row['user2']} ({$row['user2_email']}) {$row['num_movies']} times on titles {$row['movies']}\n";
}
Nick
  • 138,499
  • 22
  • 57
  • 95
  • hi!! thanks for the answer, it does work very properly, but is too long and confusing given that I have more columns than just names and emails. and it's not that necessary to display the first user's information though. also, somehow it writes everything twice and I don't know how to fix it. do you have any other solution.. maybe.?:,) – dwin812 Mar 07 '19 at 04:14
  • 1
    @valeria in your sample data you had two profile entries for one user. Is that valid? I assumed it was a typo and corrected it in my demo. If a user can have two profiles then I would need to change the query. In terms of getting too much information, you can simply remove the fields you don't want from the `SELECT` and the `GROUP BY` parts of the query. – Nick Mar 07 '19 at 04:27
1

Put the join with profile after the join with watched that gets the other user's ID.

SELECT p.*, w2.watched, 
COUNT(*) AS num_movies, 
GROUP_CONCAT(w2.watched order by w2.watched) as movies
FROM watched AS w1
JOIN watched w2 ON w2.watched = w1.watched AND w2.users_id != w1.users_id
JOIN users AS u ON u.id = w2.users_id
JOIN profile AS p ON p.users_id = u.id
WHERE w1.users_id = $id
GROUP BY w2.users_id
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • it's neet! but did you try running it? it gives an error: `Query Error: Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS num_movies, GROUP_CONCAT(w2.watched order by w2.watched) as movies FROM watc' at line 2` and as for your question above, I only need to display the other user's names and profiles, not the first – dwin812 Mar 07 '19 at 03:58
  • @valeria I am no SQL master, but I think there is a bracket missing on the second line so `COUNT(*) AS num_movies` – Rasclatt Mar 07 '19 at 05:16
  • Yes, typo there. – Barmar Mar 07 '19 at 15:30
1

Try this

    SELECT w1.users_id AS user1,u.name as name, p.*, u.*, 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 
    JOIN users u ON u.id=w1.users_id 
    JOIN profile p ON p.users_id=w1.users_id 
    WHERE w1.users_id =1 GROUP BY user1, user2

OUTPUT enter image description here

Sundar Ban
  • 589
  • 5
  • 16
  • this one seems nice and short but somehow it doesn't work for me. does it for you? i am getting the error `Error: ER_WRONG_FIELD_WITH_GROUP: Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.u.name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by` – dwin812 Mar 07 '19 at 03:50
  • could you please provide your answer here - on https://www.db-fiddle.com/f/fU9ADMjY9mQ12rB1wVwU7F/9 .? I really like the way you did it – dwin812 Mar 07 '19 at 04:12
  • You can just run this query in your local server. – Sundar Ban Mar 07 '19 at 04:16
  • whats your error ? works for me. In your local server phpmyadmin. – Sundar Ban Mar 07 '19 at 04:17
  • `Fatal error: Uncaught Error: Call to a member function fetch_assoc() on boolean ` this happens whenever there's something wrong with the query .. i did change the id 1 to `$id` though. still nothing – dwin812 Mar 07 '19 at 04:19
  • https://stackoverflow.com/questions/35669088/call-to-a-member-function-fetch-assoc-on-boolean-in-path – Sundar Ban Mar 07 '19 at 04:20
  • thank you! it worked. the problem was in my mysql version/the `group by` statement. had to write every column in order to make it work – dwin812 Mar 07 '19 at 08:06