MySQL Inner Join Merge Rows - php

I have the following problem: I have three tables, a users table, a categories table and a user_category table which connects the two first tables with foregn keys.
users table:
id username
1 user1
... ...
categories table:
id category
1 test1
2 test2
3 test3
... ...
user_category table
id user_id category_id
1 1 1
2 1 2
3 1 3
Now I want to select all users with their categories, but I dont want to have multiple rows of the same user - instead, I want to merge all categories of a user into one category field.
SELECT users.*, categories.category FROM user_category INNER JOIN users ON users.id = user_category.user_id LEFT JOIN categories ON categories.id = user_category.category_id
The output:
id username category
1 user1 test1
1 user1 test2
1 user1 test3
But I want the following:
id username category
1 user1 test1, test2, test3
Is there a possibility to do this?

SELECT users.id, users.username, GROUP_CONCAT(categories.category) as cats
FROM user_category
INNER JOIN users ON users.id = user_category.user_id
LEFT JOIN categories ON categories.id = user_category.category_id
GROUP BY users.id, users.username
could do what you want.
See http://www.sqlines.com/mysql/functions/group_concat
With TSQL you can use smth like How Stuff and 'For Xml Path' work in Sql Server

Related

Or condition in INNER JOIN

I have a table structured as follows (points):
id1 | id2 | p1 | p2
1 3 5 7
3 1 2 4
1 2 1 7
And another table strucuted as follows (users):
id | name
1 User1
2 User2
3 User3
So now, I need a query that specifing an ID (for example 3), the query check that the ID appears in the column id1 and id2, and if it appears in one of the two columns, it gives me back the user name with id1 and id2 from the rows selected. So, for example if I specific the ID 3, the query give me back:
name1 | name2 | p1 | p2
User1 User3 5 7
User3 User1 2 4
I tried various solutions but no way to do it, I think that I need an OR condition in the INNER JOIN but I don't know if it's possible and if it's the solution.. I didn't find nothing here.
I mean something like:
INNER JOIN users ON (users.id = points.id1) || (users.id = points.id2)
Any solution for that? Thanks
Join the user table twice:
SELECT u1.name, u2.name, p.p1, p.p2
FROM points p
JOIN users u1 ON u1.id = p.id1
JOIN users u2 ON u2.id = p.id2
WHERE u1.id = 3 OR u2.id = 3
Use case statement it will give you all matching value not need restricted for one or two values
CREATE TABLE points (id1 int(2), id2 int(2), p1 int(2), p2 int(2));
INSERT INTO points VALUES(1,3,5,7);
INSERT INTO points VALUES(3,1,2,4);
INSERT INTO points VALUES(1,2,1,7);
CREATE TABLE users (id int(2), name char(23));
INSERT INTO users VALUES(1,'user1');
INSERT INTO users VALUES(2,'user2');
INSERT INTO users VALUES(3,'user3');
SELECT (CASE WHEN u.id = p.id1 THEN u.name END) AS name1,
(CASE WHEN u1.id = p.id2 THEN u1.name END) AS name2,
p1, p2
FROM points p
INNER JOIN users u ON (u.id = p.id1)
INNER JOIN users u1 ON (u1.id = p.id2);

Select rows from a table where id in another second table based on second table ids shows results top as well as next results as it is + Mysql

I have users table
users
id name
1 test1
2 test2
3 test3
4 test4
5 test5
6 test6
7 test7
8 test8
9 test9
10 test10
Payment
id userid name
1 5 test5
2 3 test3
3 9 test9
i want results like this
id name
3 test3
5 test5
9 test9
1 test1
2 test2
4 test4
6 test6
7 test7
8 test8
10 test10
i want whoever pays the amount that one should be display in top order by.
SELECT u.`id` id, u.`name` NAME
FROM users u
INNER JOIN payment p
ON u.id=p.userid
UNION
SELECT u.`id` id, u.`name` NAME
FROM users u
This will produce your desired results:
SELECT a.id, a.name, 1 AS RN
FROM users a
INNER join payments b
ON a.id=b.userid
UNION ALL
SELECT a.id, a.name, 2 AS RN
FROM users a
LEFT JOIN payments b
ON a.id=b.userid
WHERE b.id IS NULL
ORDER BY RN, a.id
The first query simply selects the id and name columns for rows that appear in the payments table.
The second query gets the id and name columns for rows that do not appear in the payments table.
The UNION ALL simply merges the results together.
Notice the 1 AS RN and the 2 AS RN that are in the queries. This is an extra column that I have added so that the results can be ordered how you wanted. You can simply ignore this when you process the data.
You can do this with LEFT JOIN and ORDER BY:
SELECT
user.id, user.name
FROM
user
LEFT JOIN
payment ON user.id = payment.userid
ORDER BY payment.id DESC, user.id
This would fulfill your requirement, "i want whoever pays the amount that one should be display in top order by". But if you want the results as shown in the results you have given:
SELECT
user.id, user.name
FROM
user
LEFT JOIN
payment ON user.id = payment.userid
ORDER BY CASE
WHEN payment.id IS NULL THEN 1
ELSE 0
END , payment.id , user.id

Mysql user subscription query fails

I have a database named socialnetwork and has 5 tables category , post_category , posts , subscribe , user.
my table structures
-------- -------------
category posts
-------- ------------
categoryID postID
categoryName post
userID
categoryID
-------------- ---------------
post_category subscribe
--------------- ---------------
postID subscriberID
categoryID categoryID
--------------
usertable
--------------
userID
userName
data's in the table
category table usertable
-------------------------- -------------------
categoryID categoryName userID userName
--------------------------- --------------------
1 film 1 jijojohn32
2 television 2 sijojohn
posts_category table subscribe table
------------------ -------------------------
postID categoryID subscriberID categoryID
--------------------- ------------------------
1 1 1 1
1 2 1 2
2 2 2 2
posts table
---------------------------------------------------
postID post userID categoryID
--------------------------------------------------
1 this post is cool 1 1
2 demo post 2 2
User 1 can subscribe to different categories and he can see the articles in the categories he subscribes. That's what i am trying to implement here. And i have this query but it's not giving me the result i want.
USE socialnetwork;
SELECT socialnetwork.usertable.userName,socialnetwork.posts.post, GROUP_CONCAT(socialnetwork.category.categoryName) as category
FROM socialnetwork.category
INNER JOIN subscribe
ON subscribe.categoryID = category.categoryID
INNER JOIN posts
ON posts.categoryID = subscribe.categoryID
INNER JOIN usertable
ON usertable.userID = posts.userID
INNER JOIN socialnetwork.post_category
ON post_category.postID = posts.postID
WHERE subscriberID = "1"
GROUP BY socialnetwork.category.categoryName
Here's the result i am getting
---------------------------------
username post category
----------------------------------
jijojohn32 this post is cool film, film
sijojohn demo post television
The result i want
---------------------------------------------
username post category
-------------------------------------------
jijojohn32 this post is cool film,television
sijojohn demo post television
I want the post from the categories he subscribed to , the username of the user posted the articles , and categories which posts reside. What's wrong in my query ?. any idea ?. thanks
You are not aggregating by the right columns. I think this is the query that you want:
SELECT ut.userName, p.post, GROUP_CONCAT(c.categoryName) as category
FROM socialnetwork.category c INNER JOIN
subscribe s
ON s.categoryID = c.categoryID INNER JOIN
posts p
ON p.categoryID = s.categoryID INNER JOIN
usertable ut
ON ut.userID = p.userID INNER JOIN
socialnetwork.post_category pc
ON pc.postID = p.postID
WHERE subscriberID = 1
GROUP BY ut.userName, p.post;
Here's the working query. I made some modifications in the table. Deleted the categoryID from posts. Made a new table called post_category.
--------------
post_category
-------------
postID
categoryID
Here's the query
SELECT GROUP_CONCAT(category.categoryName) as category , category.categoryID , subscribe.subscriberID , posts.post ,
usertable.userName
from category
INNER JOIN subscribe
ON subscribe.categoryID = category.categoryID
INNER JOIN post_category
ON category.categoryID = post_category.categoryID
INNER JOIN posts
ON posts.postID = post_category.postID
INNER JOIN usertable
ON usertable.userID = posts.userID
WHERE subscriberID = 1
GROUP BY post_category.postID
There exists a conflict
Category table consists of
Category id and Category Name
Post Table consists of
Post id and Corresponding Category Id
As well as
Post_Category table consists of
Post id and Category Id
Hence it is picking from the Posts table, that
Row 1 - has only 1 category id associated with it
I suggest you remove Category id from Posttable
It is pointless to have 2 keys in 1 table, and similar 2 keys in other table.
Try to establish Primary key Foreign key relationship.
Hope that helps

SQL: Get null as a return value for rows that don't match query

I have a table, Entity and a table Friends. I want to get the names of people who have visited the same location, but I only want to return them if they are not friends with the person (suggested friend query). In order to do this I have written the following query:
SELECT Entity_Id,
Category AS FC
FROM entity
LEFT
JOIN friends
ON entity.Entity_Id = friends.Entity_Id1
OR entity.Entity_Id = friends.Entity_Id2
WHERE Entity_Id IN ( :list_of_ids )
AND Entity_Id != :user_id
AND Category != 4
GROUP
BY Entity_Id
:list_of_ids is a comma separated list of user id's and in my test query there are 82 users, however only 15 users are returned from the query, where the users returned are users who have a relationship with :user_id.
Any user who does not have a relationship in the table is not returned in the query. I thought by providing a LEFT OUTER JOIN it would return NULL for fields that were not found in the friends table.
----- EXPECTED -----
--------------------
Entity_Id FC
--------------------
1 3
2 2
3 2
4 null
52 null
64 null
------ ACTUAL -------
---------------------
Entity_Id FC
---------------------
1 3
2 2
3 2
The structure of my friends table is as follows, also note that it supports reciprocal relationships if that is any help...
------ FRIENDS ------
---------------------
fid PK
entity_id1 INT
entity_id2 INT
category INT -- 1 = Facebook, 2 = G+, 3 = App, 4 = Blocked
How can I return the users who have a missing relationship?
You want a left outer join. But, with a left join, the conditions on the second table need to go into the on clause:
SELECT e.Entity_Id, f.Category AS FC
FROM entity e LEFT JOIN
friends f
ON e.Entity_Id IN (f.Entity_Id1, f.Entity_Id2) AND
f.category <> 4
WHERE e.Entity_Id IN ( :list_of_ids ) AND
e.Entity_Id <> :user_id
GROUP BY e.Entity_Id;
When you have the condition on category in the WHERE clause, you turn the LEFT JOIN into an INNER JOIN. When there is no match, category has a value of NULL, which fails the comparison.
Which table does the Category belong to? If its a friends column, move Category != 4 from WHERE to ON to get true outer join. (Otherwise it executes as a regular innner join...):
SELECT Entity_Id, Category AS FC
FROM entity
LEFT JOIN friends
ON (entity.Entity_Id = friends.Entity_Id1
OR entity.Entity_Id = friends.Entity_Id2)
AND Category != 4
WHERE entity.Entity_Id IN ( :list_of_ids )
AND entity.Entity_Id != :user_id
GROUP
BY Entity_Id

Select each first record with id in another table's result

I have two tables, Users(id, username) and Posts(id, user_id, content). I want to list a summary of them which, I want to list all users and the first post of each user. How can I realize this in one query?
I tried something like.
QUERY
SELECT Users.*, Posts.content
FROM Users, Posts
WHERE Posts.user_id=T_Users.id
But it will return all posts for each user (I cannot add LIMIT 1 at the tail of course which only returns one user).
Some sample records:
Users table:
id username
1 test1
2 test2
Posts table:
id user_id content
1 1 This is a test1's content.
2 1 This is another test1's content.
3 2 This is a test2's content.
And I want the result:
Users.id Users.username Posts.content
1 test1 This is a test1's content.
2 test2 This is a test2's content.
Here is one approach to get the latest record per user i assume the latest record will be considered as the minimum post id
SELECT u.*, p.content
FROM Users u
join Posts p on p.user_id=u.id
join (select user_id ,min(id) id from Posts group by user_id ) p1
on (p.id = p1.id and p.user_id = p1.user_id )
Demo
Try this
select min(x.id) as Id,x.user_id,x.content from(
select p.id,p.user_id,p.content from Users u inner join Posts p
on u.id=p.user_id and u.gender=1
)x group by x.user_id
Have you tried group by clause.
SELECT Users.*, Posts.content
FROM Users, Posts
WHERE Posts.user_id=T_Users.id GROUP BY Posts.user_id

Categories