Mysql GROUP_CONCAT return only one value - mysql

I try to return how many friends a user have through GROUP_CONCAT But i only get Lance and not also Bob and it seems if i remove the WHERE condition. It works fine, but i would like to keep it. Since i want get all rows which are connected to member
CREATE TABLE users(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255)
);
INSERT INTO users (name)
VALUES ("Gregor"),
("Liza"),
("Matt"),
("Tim"),
("Lance"),
("Bob");
CREATE TABLE committee(
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
friend_id INT,
member_id INT,
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`),
FOREIGN KEY (`friend_id`) REFERENCES `users` (`id`),
FOREIGN KEY (`member_id`) REFERENCES `users` (`id`)
);
INSERT INTO committee (user_id, friend_id, member_id)
VALUES (3, 5, 1),
(4, 5, 1),
(3, 6, 2),
(4, 6, 2);
Here is the query:
SELECT u.name,
GROUP_CONCAT(f.name) AS friends
FROM committee c
INNER JOIN users u ON (u.id = c.user_id)
INNER JOIN users AS f ON (f.id = c.friend_id)
WHERE (c.member_id = 1)
GROUP BY u.id;
What i get now:
name friends
Matt Lance
Tim Lance
What i expect:
name friends
Matt Lance,Bob
Tim Lance,Bob

You need another join with committee to find all the other committees that Matt and Tim are on, so you can find their friends from those committees.
SELECT u.name,
GROUP_CONCAT(f.name) AS friends
FROM committee c
INNER JOIN users u ON (u.id = c.user_id)
INNER JOIN committee c2 ON c2.user_id = c.user_id
INNER JOIN users AS f ON (f.id = c2.friend_id)
WHERE (c.member_id = 1)
GROUP BY u.id;
DEMO

Related

Mysql SELECT multiple users key if id exsist in the row

I would like to fetch all users.myKey from the table committee if the id is in the table.
CREATE TABLE users(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
myKey VARCHAR(100)
);
INSERT INTO users (name, myKey)
VALUES ("Gregor", "kx4ht"),
("Liza", "1lPxk"),
("Matt", "mP3fd"),
("Bob", "zStr5");
CREATE TABLE committee(
user_id INT,
friend_id INT,
member_id INT,
PRIMARY KEY (`user_id`, `friend_id`, `member_id`),
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`),
FOREIGN KEY (`friend_id`) REFERENCES `users` (`id`),
FOREIGN KEY (`member_id`) REFERENCES `users` (`id`)
);
INSERT INTO committee (user_id, friend_id, member_id)
VALUES (4, 1, 3),
(1, 2, 3);
What i got now:
SELECT u.myKey FROM users u INNER JOIN committee c ON (c.user_id = u.id || c.friend_id = u.id || c.member_id = u.id) WHERE u.id = 2 GROUP BY u.id;
Result now:
I get only my own myKey user_id2
What i expect:
I want only get the myKeys for the others inside committee. E.g if i user 2 want get the myKeys from table committee where i can find my user id 2
In this case it should return the myKey for user1 and user3
As far as I understand your problem, you want to find a specific id in the "committee" table, find the id's that are next to the specified id and then find those neighboring ids in the "users" table and show their keys.
This is what I have come up with:
SELECT u.id, u.myKey
FROM users u
LEFT JOIN (SELECT IF (tmp.user_id = 2, NULL, tmp.user_id) AS user_id,
IF(tmp.friend_id = 2, NULL, tmp.friend_id) AS friend_id,
IF(tmp.member_id = 2, NULL, tmp.member_id) AS member_id
FROM (SELECT *
FROM committee
WHERE user_id = 2 OR friend_id = 2 OR member_id = 2) AS tmp) AS id_table
ON u.id = id_table.user_id OR u.id = id_table.friend_id OR u.id = id_table.member_id
WHERE user_id IS NOT NULL OR friend_id IS NOT NULL OR member_id IS NOT NULL;
Note that I am searching for the user with the id 2, as you specified.
The result of this query, as you said you would have expected it:
id | myKey
1 kx4ht
3 mP3fd

MySQL join dataset on at least X items

My question in a SQL Fiddle.
How can I join all elements in table A with all elements in table B via a many-to-many mapping table, even if no relationship exists? My LEFT JOIN solution isn't giving the results I expect.
Details:
Given these tables:
CREATE TABLE `user` (
id INT PRIMARY KEY NOT NULL,
email VARCHAR(100) NOT NULL
);
CREATE TABLE `event` (
id INT NOT NULL,
start_time DATETIME NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE `event_response` (
id INT PRIMARY KEY NOT NULL,
user_id INT NOT NULL,
event_id INT NOT NULL,
response VARCHAR(5) NOT NULL,
FOREIGN KEY (user_id)
REFERENCES `user`(id)
ON DELETE CASCADE,
FOREIGN KEY (event_id)
REFERENCES `event`(id)
ON DELETE CASCADE
);
And this seed data:
-- create some users
INSERT INTO `user`(`id`, email)
VALUES
(1, 'abc1#gmail.com'),
(2, 'abc2#gmail.com'),
(3, 'abc3#gmail.com');
-- create two events
INSERT INTO `event`(`id`, start_time)
VALUES
(1, '2020-09-01'),
(2, '2020-10-01');
-- Only 3 users have responded to the events
INSERT INTO `event_response`(`id`, user_id, event_id, response)
VALUES
(1, 1, 1, 'yes'),
(2, 2, 1, 'no'),
(3, 3, 2, 'yes');
I need a report like this:
start_time, email, response
"2020-09-01", abc1#gmail.com, yes
"2020-09-01", abc2#gmail.com, no
"2020-09-01", abc3#gmail.com, <NO RESPONSE>
"2020-10-01", abc1#gmail.com, <NO RESPONSE>
"2020-10-01", abc2#gmail.com, <NO RESPONSE>
"2020-10-01", abc3#gmail.com, yes
The query I have tried (but doesn't give satisfactory results):
SELECT
e.start_time,
u.email,
COALESCE(er.response, '<NO RESPONSE>') AS response
FROM `user` AS u
LEFT JOIN event_response AS er ON u.id = er.user_id
LEFT JOIN `event` AS e ON er.event_id = e.id
ORDER BY e.start_time ASC;
Use a cross join to generate the rows and left join to bring in the values:
select e.*, u.*, er.response
from event e cross join
user u left join
event_response er
on er.user_id = u.id and er.event_id = e.id;

Select all Courses, and for those in which a certain Student is enrolled, also select the Enrollment data

Classic Student-Enrollment-Course structure, but the Enrollment join table has an additional DATE column. Here's a sample fiddle: http://sqlfiddle.com/#!9/81d3e5/3.
CREATE TABLE student (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL
);
CREATE TABLE course (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL
);
CREATE TABLE enrollment (
student_id INT NOT NULL,
course_id INT NOT NULL,
enrollment_date DATE NOT NULL,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id)
);
INSERT INTO student (name) VALUES
("Alice"),
("Bob");
INSERT INTO course (name) VALUES
("CS 101"),
("Relational Algebra"),
("Compilers");
INSERT INTO enrollment (student_id, course_id, enrollment_date) VALUES
(1, 1, '2020-01-13'),
(1, 2, '2020-02-05'),
(2, 2, '2020-02-07');
A student needs to see a list of all available courses, and if they're enrolled, the enrollment date. Here's the desired result for student ID 2:
+--------------------+-----------------+
| course_name | enrollment_date |
+--------------------+-----------------+
| CS 101 | null |
| Relational Algebra | 2020-02-07 |
| Compilers | null |
+--------------------+-----------------+
It's been a few years since I did anything more complicated than a simple left join, and I can't figure this one out.
You can create a INNER table and left join the result of the table with the course table.
Note: student table is optional I just used so that you can retrieve student information as well
SELECT
c.name course,
es.enrollment_date
FROM course c
LEFT JOIN
(SELECT course_id , e.`enrollment_date` from enrollment e , student s where e.student_id = s.id and s.id=3)
AS es on c.id = es.course_id;
SELECT course.name, t1.enrollment_date
FROM course
LEFT JOIN (SELECT * FROM enrollment WHERE enrollment.student_id = 2) AS t1
ON course.id = t1.course_id;
Use below query, left outer join will provide you your expected result
select c.name as course_name, e.enrollment_date from course c
left outer join enrollment e
on (c.id = e.student_id);
select c.name as course_name, e.enrollment_date from course c
left outer join enrollment e
on (c.id = e.student_id)
where e.student_id = 2;

How to get distinct pairs for a table?

Tables
CREATE TABLE Users (user_id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL);
CREATE TABLE Ratings (user_id INTEGER NOT NULL,
rating INTEGER NOT NULL,
movie_name varchar(100) NOT NULL,
PRIMARY KEY(user_id, movie_name),
FOREIGN KEY (user_id) REFERENCES Users(user_id));
CREATE TABLE Similarity (user1_id INTEGER NOT NULL,
user2_id INTEGER NOT NULL,
similarity FLOAT,
PRIMARY KEY (user1_id, user2_id),
FOREIGN KEY (user1_id) REFERENCES Users(user_id),
FOREIGN KEY (user2_id) REFERENCES Users(user_id));
Query: Find all distinct user pairs with a Similarityi,j >= 0.7 whose watch list overlaps in at least 12 movies. The result should contain three columns: the user id of the first user and the user id of the second user, and the number of movies they have watched.
My Query: Returns null
SELECT DISTINCT U.user_id, U2.user_id
FROM Users U, Users U2, Ratings R, Similarity S
WHERE U.user_id != U2.user_id AND
R.user_id = U.user_id AND
R.user_id = U2.user_id AND
S.similarity >= 0.7;
I realized U.user_id != U2.user_id AND R.user_id = U.user_id AND R.user_id = U2.user_id makes the table return null. But how do I get distinct user_id pairings?
You need to join the tables
e.g.
FROM User U
JOIN Ratings R ON U.user_id = R.User_id
JOIN Similarity S ON S.user2_id = U.user_id
I would join them first and then use your where clause

How to find friends of friends who are not my friends in two way relationship in SQL

My data set:
CREATE TABLE `users` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL COLLATE `utf8mb4_bin`,
PRIMARY KEY (`id`)
)
COLLATE=`utf8mb4_bin`
ENGINE=InnoDB
;
CREATE TABLE `friends` (
`friend_one` INT(11) NOT NULL,
`friend_two` INT(11) NOT NULL,
`status` INT(11) NULL DEFAULT NULL,
`requested_id` INT(11) NOT NULL,
UNIQUE INDEX `friend_one_friend_two` (`friend_one`, `friend_two`),
INDEX `IDX_FRIEND_ONE` (`status`, `friend_one`, `friend_two`),
INDEX `IDX_FRIEND_TWO` (`status`, `friend_two`, `friend_one`),
CONSTRAINT `FK_FRIEND_ONE` FOREIGN KEY (`friend_one`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `FK_FRIEND_TWO` FOREIGN KEY (`friend_two`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE=`utf8mb4_bin`
ENGINE=InnoDB
;
INSERT INTO users(id, username) VALUES
(1, 'A'),
(2, 'B'),
(3, 'C');
INSERT INTO friends(friend_one, friend_two, status, requested_id) VALUES
(1, 2, 1, 1),
(1, 3, 1, 1);
SQLfiddle of same: http://sqlfiddle.com/#!9/10dba9/5
I would like to fetch friends of friends from my friends table.
I enforce friend_one is always smaller than friend_two (1 < 2)
and always assume 1 -> 2 friend relationship is 2 -> 1 using status key (0 being pending, 1 being friends)
Now I wish to get friends of friends:
1 -> 2 and 1 -> 3 are friends and I wish to recommend 2 to 3 or 3 to 2 saying
"You have a mutual friend 1!"
This is how I get friends
SELECT u.id, u.username, f.friend_one, f.friend_two, f.status, f.requested_id
FROM users u
JOIN friends f
ON f.status = 1 AND f.friend_one = 1 AND f.friend_two = u.id
UNION ALL
SELECT u.id, u.username, f.friend_one, f.friend_two, f.status, f.requested_id
FROM users u
JOIN friends f
ON f.status = 1 AND f.friend_two = 1 AND f.friend_one = u.id
UPDATE 1
I referred to this but it looks like the table does not enforce id 1 < id 2
Finding mutual friend in one way relationship table
UPDATE 2
I think I found a solution in here
Sql to get all the friends of friends who's not my friend
I do not know whether this one inner join will affect the performance. Is there a way to use join in this case?
SELECT u.id, u.user_id, u.username, F2.friend_two, F2.status
FROM friends F
JOIN friends F2
ON F.friend_two = F2.friend_one
JOIN users u
ON u.id = F2.friend_two
WHERE F2.friend_two NOT IN (SELECT friend_two
FROM friends
WHERE friend_one = 2)
AND F.friend_one = 2
AND F2.`status` < 1
OR NULL
GROUP BY F2.friend_two
ORDER BY F2.friend_two;