How to get mysql result in following format - mysql

Database Tables:
The below tables contain the information about users and their licenses.
Note: One user can have multiple licenses.
users table
Users( 'user_id', 'user_email', 'name' )
license table
Licenses( 'license_id', 'user_id', 'license_key', 'license_status' )
Write an optimized MySql query to generate the output like
Desired output
Edit:
I have tried this SELECT u.user_email, u.name as user_name, l.license_status as status, l.license_key FROM users u left join licenses l on u.user_id = l.user_id but it's not showing expected result and I'm not sure how can I get the Desired output

GROUP_CONCAT to the rescue:
SELECT u.user_email,
u.name as user_name,
GROUP_CONCAT(l.license_status ORDER BY license_id) AS statuses,
GROUP_CONCAT(l.license_key ORDER BY license_id) AS "keys"
FROM users u
left join licenses l ON u.user_id = l.user_id
GROUP BY u.user_id
If desired change to
COALESCE(GROUP_CONCAT(...), "none") AS ...
If you don't want the users with no licenses, change LEFT JOIN to JOIN.

Related

How to count a number from different table when there's no common field?

There are a user table and a user_follow table that describes which user.id is following/followed. I'd like to count the occurrences of that user is following and being followed.
The problem is that user_follow table doesn't have user_id as a foreign key, so I'm not able to join enter image description here the two tables by a common field. I've tried to use LEFT OUTER JOIN on user.id=user_follow.following_user_id and GROUP BY user.id, but it only counts the times of following(followed times is exactly the same as the following, which is not right).
The way to solve this is to join on USER_FOLLOW twice, once for Followed By and once for Following.
You haven't posted the structure of USER_FOLLOW, so this is a guess and you'll need to correct it to fit your schema.
select u.id, u.first_name, u.last_name
, count(f.following_user_id) as following_count
, count(fb.user_id) as followed_by_count
from user u
left_outer join user_follow f on where f.user_id = u.id
left_outer join user_follow fb on where fb.following_user_id = u.id
group by u.id, u.first_name, u.last_name

Paginating a large user database with joins

I have a wordpress user database table 100,000+ users. As part of a plugin I need to list the subscribers. Obviously getting 100,000 users needs to be paginated. To get the total number of users to work out the pagination, I am running the main query without a limit and doing a PHP count() on the results:
SELECT role.umeta_id, role.user_id, role.meta_key, role.meta_value role, u.ID, u.user_login, u.user_email, u.user_registered
FROM wp_users AS u
LEFT JOIN wp_usermeta role ON role.user_id = u.ID
AND role.meta_key = 'wp_capabilities'
WHERE role.meta_value LIKE '%subscriber%'
GROUP BY u.ID
ORDER BY u.ID ASC
I am (unsurprisingly) running out of memory doing this. I have tried just doing a count similar to
SELECT COUNT( u.ID )
FROM wp_users AS u
LEFT JOIN wp_usermeta role ON role.user_id = u.ID
AND role.meta_key = 'wp_capabilities'
WHERE role.meta_value LIKE '%subscriber%'
GROUP BY u.ID
ORDER BY u.ID ASC
but rather than returning a single value, this returns rows and rows of count = 1.
I know that there are get_user functions in Wordpress to do this - I am just using this as a simplified example (the query is actually more complex)
So the question is "How can I efficiently get the total number of rows in such a situation as this?"
The problem with your query is that you're grouping by u.ID and count is an aggregate function
Edited:
I suggest getting rid of the group and the order by to where you're left with this
SELECT COUNT( u.ID )
FROM wp_users AS u
LEFT JOIN wp_usermeta role ON role.user_id = u.ID
AND role.meta_key = 'wp_capabilities'
WHERE role.meta_value LIKE '%subscriber%'

mysql joining for relational lookup

I've never been all that great with much more then regular select queries. I have a new project that has users, roles and assigned_roles (lookup table for users with roles).
I want to group_concat the roles.name so that my result shows me what roles each user has assigned.
I've tried several things:
select users.id, users.displayname,users.email, rolenames from `users`
left join `assigned_roles` on `assigned_roles`.`user_id` = `users`.`id`
left join (SELECT `id`, group_concat(`roles`.`name`) as `rolenames` FROM `roles`) as uroles ON `assigned_roles`.`role_id` = `uroles`.`id`
This gives me the grouped role names but shows me duplicate entries if a user has two roles, so the second row in the result shows the same user but no role names.
select users.id, users.displayname,users.email, rolenames from `users`
join `assigned_roles` on `assigned_roles`.`user_id` = `users`.`id`
join (SELECT `id`, group_concat(`roles`.`name`) as `rolenames` FROM `roles`) as uroles ON `assigned_roles`.`role_id` = `uroles`.`id`
Just regular joins shows me what I want but wont lists users who do not have any assigned.roles, so its not complete.
I'll keep plugging away but I thought stack could help, hopefully I'll learn a bit more about joins today.
Thank you.
For GROUP CONCAT to work in this scenario, you'll need a GROUP BY to get the group info per user, something like;
SELECT u.id, u.displayname, u.email, GROUP_CONCAT(r.name) rolenames
FROM users u
LEFT JOIN assigned_roles ar ON ar.user_id = u.id
LEFT JOIN roles r ON r.id = ar.role_id
GROUP BY u.id, u.displayname, u.email

MYSQL JOIN syntax How to Join Three Tables

The following query does what I want. It returns all the resuls in the users table and then if there is a match in the details tble, returns the relevant data
users
id|username
details
id|userid|firstname|lastname
$sql = "SELECT u.*, d.*
FROM `users` u
LEFT JOIN `details` d on
u.id = d.userid
ORDER BY $strorder";
However, when I try to join an additonal table where I want to do the same thing--return all the results of the users table and if there is a match in the third table, return the relevant data (total followers of this user)--it only returns one record.
3rd table
follow
id|followerid|followedid
$sql = "SELECT u.*, d.*, COUNT(f.id)
FROM `users` u
LEFT JOIN `details` d on
u.id = d.userid
LEFT JOIN `follow` f on
u.id = f.followedid
ORDER BY $strorder";
Can anyone see what I am doing wrong? Thanks in advance for any suggestions.
Many thanks.
Try to avoid * to select fields, it will be clearer to group your datas (even if mysql is quite permissive with groupings).
When you have an aggregate function (like COUNT, SUM), the other "non aggregated" requested fields should be in a GROUP BY clause.
Mysql don't force you to GROUP BY all the fields, but... I think it's quite a good habit to be "as ANSI as possible" (usefull when you use another DBMS)
SELECT u.id, u.username, d.firstname, d.lastname, count(*) as numberfollowers
FROM user u
LEFT JOIN details d on u.id = d.userid
LEFT JOIN follow f on u.id = f.followedid
GROUP BY u.id, u.username, d.firstname, d.lastname --or just GROUP BY u.id with Mysql
ORDER BY count(*) desc
COUNT being an aggregate function, when selected with other columns, requires you to group your results by those other columns in the select list.
You should rewrite your query with columns that you want to select from users and details and group by those columns.

mysql where OR having

I have a table of users, some of which have articles associated with them, and some of which have type = writer. I'd like to display all users who have articles OR who have type = writer. So, all writers should be displayed, and other user types are only displayed if they have articles.
This is my query so far, which leaves out writers with no articles.
SELECT u.name, u.type, COUNT(a.id) count
FROM users u
LEFT JOIN articles a on u.id = a.writer_id
GROUP BY u.name
HAVING count > 0
Adding the following WHERE clause obviously excludes other user types that have articles.
WHERE u.type = 'writer'
Do I need to do a UNION of these two result sets?
I think you are looking for something like this
SELECT
u.name,
u.type,
COUNT(a.id) count
FROM users u
LEFT JOIN articles a ON u.id = a.writer_id
WHERE
u.type='writer' --all users that are writers
OR
a.writer_id IS NOT NULL --all users that have at least one article
GROUP BY
u.name
--removed the having clause as it seems it may be possible that a writer has no articles.
Just change the WHERE clause to allow any user that has a matching article record:
SELECT u.name, u.type, COUNT(a.id) count
FROM users u
LEFT JOIN articles a on u.id = a.writer_id
WHERE u.type = 'writer' OR a.writer_id IS NOT NULL
GROUP BY u.name
HAVING count > 0