newbie mysql query expecting delimited string - mysql

here's my data structure:
users
id user
-----------------------
1 foo
2 bar
rooms_available
id id_user name
----------------------
1 2 room #1
2 2 room #2
3 2 room #3
4 2 room #3
i would like getting the following result:
id_user user rooms
-----------------------------
2 bar 1,2,3,4
any ideas?
thanks

You should use GROUP_CONCAT. For example:
SELECT users.id as id_user,
users.name as user,
GROUP_CONCAT(DISTINCT rooms_available.id) as rooms
FROM users
JOIN rooms_available ON users.id = rooms_available.id_user

select u.id as id_user, a.user, b.rooms
from
users u
inner join (select id_user, group_concat(`name`) as rooms from rooms_available group by 1) b on u.id=b.id_user

Try this:
SELECT a.id, a.user, GROUP_CONCAT(DISTINCT b.id ORDER BY b.id)
FROM users a
JOIN rooms_available b
ON a.id = b.id_user

Related

SQL - nested joins

I have a mySQL database in which I'm trying to output a list of users and their assigned, administrative roles. My tables look something like:
Users:
-------
- id
- fname
- lname
Role_Names
-----------
- rn_id
- role_name
Roles
---------
- role_id
- user_id
here's some data:
Users:
-------
1 'Chris' 'Christy'
2 'Brian' 'Bobson'
3 'Jen' 'Sanders'
Role_Names
--------------
1 'admin'
2 'exec'
3 'employee'
Roles
-----------
1 1
1 2
1 3
2 3
3 3
3 2
and for my query, I'm using:
SELECT Users.fname, Role_Names.role_name from Users INNER JOIN
Roles on Users.id = Roles.user_id
INNER JOIN Role_Names
ON Roles.rn_id = Roles.role_id;
It only seems to be outputting roles for the 1st user_id in the Roles table. And it's outputting more than 1 of the same record. For example, my output looks like:
first_name role_name
--------------------------------------
Chris exec
Chris     exec
Chris exec
Chris employee
Chris employee
Chris employee
Chris admin
Chris admin
Chris admin
whereas I was hoping for something more like:
first_name role_name
--------------------------------------
Chris employee
Chris admin
Chris exec
Brian employee
Jen employee
Jen exec
...
At tis point I'm not sure if it's my table structure that is flawed or if I'm using joins incorrectly or if it's that plus a bunch of other stuff I don't even know about. Can someone help point me in the right direction?
Stare at this piece of your query: ON Roles.rn_id = Roles.role_id;
It is not what you meant!
Here is the fixed query (with clearer formatting):
SELECT Users.fname, Role_Names.role_name
FROM Users AS u
INNER JOIN Roles AS r ON u.id = r.user_id
INNER JOIN Role_Names AS rn ON rn.rn_id = r.role_id
Tip: Many:many mapping tables (your Roles) are typically named by the the two things it relates. So I suggest User_Roles. Then the 3rd table can be simply Roles. That leads to
SELECT Users.fname, Role_Names.role_name
FROM Users AS u
INNER JOIN User_Roles AS ur ON u.id = ur.user_id
INNER JOIN Roles AS r ON r.rn_id = ur.role_id
use distinct
with Users as
(
select 1 id, 'Chris' fname, 'Christy' lname
union all
select 2 , 'Brian', 'Bobson' union all
select 3 ,'Jen' , 'Sanders'
),Role_Names as
(
select 1 rn_id, 'admin' role_name
union all
select 2 , 'exec' union all
select 3 , 'employee'
) , Roles as
(
select 1 role_id,1 user_id
union all
select 1,2 union all
select 1,3 union all
select 2 , 3 union all
select 3 , 3 union all
select 3 , 2
) SELECT distinct Users.fname, Role_Names.role_name
from Users left JOIN
Roles on Users.id = Roles.user_id
left JOIN Role_Names
ON Role_Names.rn_id = Roles.role_id
you missed join in your query
JOIN Role_Names ON Roles.rn_id = Roles.role_id -- here both side you use Roles
You can use DISTINCT like following.
SELECT DISTINCT Users.fname, Role_Names.role_name from Users INNER JOIN
Roles on Users.id = Roles.user_id
INNER JOIN Role_Names
ON Roles.rn_id = Roles.role_id;
Try using below query.
SELECT Users.fname, Role_Names.role_name
from Roles RIGHT OUTER JOIN
Users on Users.id = Roles.user_id
INNER JOIN Role_Names
ON Roles_Names.rn_id = Roles.role_id;

MySQL order results by the sum of two relations count(*)

I would like to order the results by the count(*) of two related tables entries.
So I would like to get the top ordered user IDs that have more comments + posts interactions.
User Table:
ID Name ...
1 Jonh
2 Mark
3 King
4 Doe
Post Table:
ID USER_ID...
1 1
2 1
3 3
4 1
Comment Table:
ID USER_ID...
1 1
2 3
3 1
4 4
Ordered by POSTs count(*):
SELECT user.*, COUNT(post.user_id) AS count FROM user
LEFT JOIN post ON user.id = post.user_id
GROUP BY user.id
ORDER BY count DESC
Ordered by COMMENTs count(*)
SELECT user.*, COUNT(comment.user_id) AS count FROM user
LEFT JOIN comment ON user.id = comment.user_id
GROUP BY user.id
ORDER BY count DESC
Ordered by POSTs + COMMENTs count(*)
Expected Result:
user_id: 1 (four interactions), 3 (two interactions), 4 (one interaction)
SELECT u.*, COUNT(interact.user_id)
FROM user u
LEFT JOIN ( SELECT user_id FROM post
UNION ALL
SELECT user_id FROM comment
) interact
ON u.user_id = interact.user_id
GROUP BY u.user_id
If you want more detail can use conditional count
SELECT u.*,
COUNT(CASE WHEN source = 'p' then 1 END) as total_p,
COUNT(CASE WHEN source = 'c' then 1 END) as total_c,
COUNT(interact.user_id) as total_interact
FROM user u
LEFT JOIN ( SELECT user_id, 'p' as source FROM post
UNION ALL
SELECT user_id, 'c' as source FROM comment
) interact
ON u.user_id = interact.user_id
GROUP BY u.user_id

MySQL select query from two tables

I have two tables: users and works
I need write select query for count different names from users table where work_status = 1 from works table
The total is: 3 John, 1 Tom
I need get result:
John 2 (2 because one John work_status = 0 ant this not counting)
Tom 1
I have write select that can count different names, just need compared work_status..
SELECT name,COUNT(*) as num FROM users GROUP BY name
My query return:
There is a problem in your question. So here you have two solutions.
If there are three different John working on the company, this is your query
SELECT u.name, COUNT(*) as num
FROM users u INNER JOIN works w ON w.user_id = u.id
WHERE w.work_status = 1
GROUP BY u.name, u.id
If there are only one John working in the company, your query is this one:
SELECT u.name, COUNT(*) as num
FROM users u INNER JOIN works w ON w.user_id = u.id
WHERE w.work_status = 1
GROUP BY u.name
Note: If three John are the same person, you should delete the 2 last and on the works table change user_id = 3 and user_id = 4 for user_id = 1
This is a simple JOIN query:
SELECT u.name, COUNT(*) num
FROM users u
JOIN works w
ON w.user_id = u.id
AND w.work_status = 1
GROUP BY u.name
This one should do the job:
SELECT users.name,SUM(works.work_status) as num
FROM users,works
WHERE users.id=works.id
GROUP BY name
SELECT
users.`name`,
COUNT(*) num
FROM
users,
works
WHERE users.`id` = works.`user_id`
AND works.`work_status` = 1
GROUP BY users.`name` ;

Select rows in order of total count

I have a table of users which hold a a users id that they voted for like this:
uid | voted_for
1 | 3
2 | 3
3 | 1
What i'm aiming to do is order uid based on how many people have voted for that uid. But I have no idea how to do it.
So the end result would be:
uid | Total_Votes
3 | 2
1 | 1
2 | 0
Hope you can help explain the best way to structure the SQL for this.
Perhaps something like this will help joining the table on itself:
SELECT u.*, voted_for_cnt
FROM users u
LEFT JOIN (
SELECT voted_for, count(1) voted_for_cnt
FROM users
GROUP BY voted_for
) t ON u.uid = t.voted_for
ORDER BY t.voted_for_cnt DESC
SQL Fiddle Demo
This simple query will produce the output you requested:
select voted_for as uid, count(*) as total_votes
from users
group by 1
order by 2 desc
If you want all data about each user in the output, join users to itself:
select u.*, count(v.uid) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2,3,4,5 -- put as many numbers here as there are columns in the users table
order by total_votes desc
This second query will give a total_votes score of zero if no one voted for the user.
Alternatively, you can select only those columns you want:
select u.uid, u.name, count(v.uid) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2
order by 3 desc
```
To return only the winners, do this:
select u.uid, u.name, count(*) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2
having count(*) = (
select max(c) from (
select count(*) as c from users group by voted_for))
order by 3 desc

Multiple table JOIN issue

first, you should know that i suck big time at SQL.
Here is my problem:
I have 4 tables that i need to be joinned (for usage in SphinxSearch), here is the rough structure:
Accounts
Id Name Category
----------------
1 Test 1
2 Foo 2
3 Bar 1
Category
Id Name
-------
1 Restaurants
2 Store
Accounts_has_subcategory
account_id subcat_id
--------------------
1 1
1 3
2 2
Subcategory
Id Name
-------
1 Chinese
2 Sportswear
3 Delivery
What i want is a resultset looking like this:
accounts.id | accounts.name | category_name | subcategories
-----------------------------------------------------------
1 Test Restaurants Chinese, Delivery
2 Foo Store Sportswear
Right my query looks like this:
SELECT a.id, a.name, c.name as category, group_concat(subcat.name) as subcategories
FROM accounts AS a
JOIN (account_has_subcategory AS ahs, subcategory AS subcat)
ON (a.id = ahs.account_id AND ahs.subcat_id = subcat.id),
accounts AS a2
JOIN category AS c
ON a2.category = c.id
Like said before, i suck at SQL (as soon as it involves multiple joins or stuff like that basically...). If someone could point me in the right direction or offer a solution (with basic explanation, so i can try and get that in my brain -_-), that would make my day since i've been fighting that query for a good 5h now...
Thanks.
Try this?
SELECT a.id, a.name,
c.name as category,
group_concat(subcat.name) as subcategories
FROM accounts AS a
INNER JOIN account_has_subcategory AS ahs ON a.id = ahs.account_id
INNER JOIN subcategory AS subcat ON subcat.id = ahs.subcat_id
INNER JOIN category AS c ON a.category = c.id
GROUP BY a.id, a.name, c.name
ORDER BY a.id;
You're almost there - you just need to fix up your syntax a little and add a group by.
select a.id, a.name, c.name as category, group_concat(subcat.name) as subcategories
from accounts as a
inner join category as c on a.category = c.id
inner join accounts_has_subcategory as ahs on a.id = ahs.account_id
inner join subcategory as subcat on ahs.subcat_id = subcat.id
group by a.id, a.name, c.name