MySQL: How to count rows when multiple joined tables? - mysql

MySQL: How to count rows when multiple joined tables ??
+Query:
SELECT p.role FROM users u
INNER JOIN roles r ON r.id=u.role
INNER JOIN permissions p ON p.role=r.id
WHERE p.p_id=19 AND p.p_update=1 AND r.active=1
GROUP BY p.role
+Result:
________
|p_role:|
|_______|
| 1 |
| 4 |
|_______|
When I add COUNT() function to p.role:
+Query:
SELECT COUNT(p.role) FROM users u
INNER JOIN roles r ON r.id=u.role
INNER JOIN permissions p ON p.role=r.id
WHERE p.p_id=19 AND p.p_update=1 AND r.active=1
GROUP BY p.role
+Result:
_______________
|COUNT(p_role):|
|______________|
| 5 |
| 1 |
|______________|
Why I see 2 records I already use COUNT() function??
I don't want to see result like this.
I want to count rows of query above.
I want to see result like this:
_______________
|COUNT(p_role):|
|______________|
| 2 |
|______________|
Please anyone help me. Thanks in advance!
Sorry for my broken English.

Because of GROUP BY clause in your query, it returns count per p.role value. If you want the query to return one value, you can remove GROUP BY, e.g.:
SELECT COUNT(DISTINCT(p.role)) FROM users u
INNER JOIN roles r ON r.id=u.role
INNER JOIN permissions p ON p.role=r.id
WHERE p.p_id=19 AND p.p_update=1 AND r.active=1;
By the way, I have added DISTINCT to the query so that it will return count of distinct p.role values. If you want the count of records only, you can remove DISTINCT.

Related

How to do a proper Inner join?

I have this app where I need to do a query and have two columns.This are my two columns and respective rows:
Name of table1: Machines(has a row called Machinesnames and a id_group as FK)
Name of table2: Groups (has a row called groupsnames and id_groups as PK)
The problem is that with the query you see below I am getting the following result
**GroupsNames** | **MachinesNames**
1 machine1
1 | machine2
1 | machine3
2 | machine4
I have done this but I think is wrong can you correct my query please?:
SELECT groups.name,Machines. Machinesnames,Groups.groupsnames FROM Machines INNER JOIN Groups ON Machines.id_group = Groups.id_group
This is the result I want to see
**GroupsNames** | **MachinesNames**
1 machine1,machine2,machine3
2 | machine4
You are looking for group_concat:
select g.name,
group_concat(m.Machinesnames)
from Machines m
inner join Groups g on m.id_group = g.id_group
group by g.name;
Your query is correct for a inner join, but from looking at your expected output you are wanting a aggregated list.
Try this answer for MySQL using GROUP_CONCAT()
Aggregate function in MySQL - list (like LISTAGG in Oracle)

Mysql select between two table without limiting if record appear on the joined table

I have been trying to figure out how to select data related to one id between to tables without limit it to the joined table. I tried using UNION, Inner join, JOIN, but it limit me to show records that are only in both tables. By example:
Table 1 (users)
id | name | register
1 | John | 2014-03-01
2 | Kate | 2014-03-02
etc..
Table 2 (birthdays by example)
id | user | birthday
1 | 1 | 1989-09-09
Note that kate dont have a record on the birthdays table, if i do:
SELECT U.id, name, register, B.birthday FROM users as U INNER JOIN birthday as B ON B.user = U.id
it will only shows JOHN data, i would like to select all my users and if the record do not exist on the joined table, still be able to select all my users, sort of:
id | name | register | birthday
1 | John | 2014-03-01 | 1989-09-09
2 | kate | 2014-03-02 | null or ''
3
4
etc.
Sorry if its a stupid question but i dont find the light on this one. I would appreciate the help.
Regards
You need a LEFT OUTER JOIN instead of the plain JOIN (also known as INNER JOIN), like this:
SELECT U.id, name, register, B.birthday
FROM users as U
LEFT JOIN birthday as B
ON B.user = U.id
A LEFT JOIN between users and birthday tables will contain all records of the "left" table (users), even if the join-condition does not find any matching record in the "right" table (birthday).
This excellent article on The Code Project will help you a lot: Visual Representation of SQL Joins.
Summary of all JOIN types:
Note: Mysql does not support FULL OUTER JOIN but it can be emulated. Useful articles:
https://stackoverflow.com/a/4796911
http://www.sql-tutorial.ru/en/book_full_join_and_mysql.html
http://www.xaprb.com/blog/2006/05/26/how-to-write-full-outer-join-in-mysql/
Use left outer join instead of inner join..
SELECT U.id, name, register, B.birthday
FROM users as U left join birthday as B ON B.user = U.id

COUNT(*) FROM different tables with LEFT JOIN

I have 1 table of users, and 10 tables (articles, news, ...) where I save user's publications. I want to show how many publications has each user, in one query:
| ID_USER | COUNT(id_article) | COUNT(id_news) | etc...
-------------------------------------------------
| 1 | 0 | 3 |
| 2 | 2 | 9 |
| 3 | 14 | 5 |
| 4 | 0 | 0 |
If I use this query to show the number of articles...
SELECT id_user,COUNT(articles.id_article) FROM users
LEFT JOIN articles ON articles.id_user_article=users.id_user
GROUP BY users.id_user
... it shows the information correctly. But if I start to add the second table...
SELECT id_user,COUNT(articles.id_article),COUNT(news.id_news) FROM users
LEFT JOIN articles ON articles.id_user_article=users.id_user
LEFT JOIN news ON news.id_user_news=users.id_user
GROUP BY users.id_user
... it doesn't show the correct information.. and if I join all the rest tables, if shows really strange result (thousands of articles for first user, and NULL for the rest).
Which is the correct way of show this information using only one query? Thank you!
You can use a subselect instead of a left join for each table. The final result will be the same but maybe in that way is clearer.
SELECT u.id_user,
(SELECT COUNT(a.id_article)
FROM articles a
WHERE a.id_user_article = u.id_user) AS articles,
(SELECT COUNT(n.news)
FROM news n
WHERE n.id_user_news = u.id_user) AS news
FROM users u
Also if you only uses one column of each table, the subselect is a better option than multiple left joins.
Your problem is that you are joining along different dimensions, which creates cartesian products for each user. The solution by #rafa is actually a fine solution in MySQL. The use of count(distinct) works okay, but only when the counts are not very large. Another approach is to pre-aggregate the results along each dimension:
SELECT u.id_user, a.articles, n.news
FROM users u left outer join
(select id_user_article, count(*) as articles
from articles
group by id_user_article
) a
on u.id_user = a.id_user_article left outer join
(select id_user_news, count(*) as news
from news
group by id_user_news
) n
on u.id_user = n.id_user_news;
EDIT:
If you are using the count(distinct) approach, then you are generating a cross product. If every user had 3 articles and 4 news items, then the users would be multiplied by 12. Probably feasible.
If every user had 300 articles and 400 news items, then every user would be multiplied by 120,000. Probably not feasible.

Trouble joining two tables - No results

I have a table named phpbb_pcp_market with these rows: http://pastebin.com/ZAFjawD8 (There are more obviously)
And I have another table named phpbb_pcp_market_cart that looks like this:
+----+---------+-----------+------------+
| id | item_id | player_id | time |
+----+---------+-----------+------------+
| 14 | 49 | 3 | 1384806292 |
+----+---------+-----------+------------+
I need to join these two tables based on item_id, but for some reason it's not working.
This is the query I've used:
SELECT m.*, c.* FROM (phpbb_pcp_market_cart c)
LEFT JOIN phpbb_pcp_market m
ON (c.item_id = m.item_id)
WHERE c.player_id = 3
ORDER BY c.time
For some reason, it's returning nothing.
I can't figure what I did wrong in the query. And no, I'm not good at SQL.
Everything looks fine with your SQL-code.
Look in the rest of your PHP-code if there is something wrong. The bug is not related to the SQL-part ;)
First double check your data, your query seems to be OK.
If you want to select all items for specific player_id don't use LEFT JOIN but simple JOIN, because you will never get rows where it could be NULL.
Also braces can be left out for simplicity:
SELECT m.*, c.* FROM phpbb_pcp_market_cart c
JOIN phpbb_pcp_market m
ON c.item_id = m.item_id
WHERE c.player_id = 3
ORDER BY c.time

mysql - selecting groups and users all in same query

I have following two tables 'USERS' and 'GROUPS':
USERS
-id
-name
-groupid
GROUP
-id
-name
I'd like to return all users along with their group's name and group id. It should be an outer join on group id field correct?
A simple INNER JOIN should be enough:
SELECT `USERS`.*, `GROUP`.name AS group_name
FROM `USERS`, `GROUP`
WHERE `USERS`.groupid = `GROUP`.id
You're going to want to look at the JOIN statement
Doing this from my phone, so pardon any moderately incorrect syntax, but something a long the lines of
Edit: other guy's syntax is better. It's too early here
You can use a LEFT JOIN between users and groups so that users who are not in a group still show up in the result set, but with group name and id NULL:
SELECT
a.*,
b.name AS group_name
FROM
users a
LEFT JOIN
`group` b ON a.group_id = b.id
Side note: Ensure that you're encasing the table name group in backticks because it is a reserved keyword.
The result-set should look something like:
id | name | group_id | group_name
-----------------------------------------------------------------------------
1 | John | 5 | ThisIsGroup5
3 | Tim | 3 | ThisIsGroup3
6 | NotInGroup | NULL | NULL
Changing LEFT to INNER in the above query would INNER JOIN the two tables and exclude the user "NotInGroup" from the result-set.