MySql Query Join 3 tables and grouping 1 - mysql

So I have the below database structure
TABLES ------- Columns
person: id, name, salary, address
group: id, name
person_group: person_id, groud_id
So here is my query which is used to get all persons along with the groups they are associated with
SELECT p.id, p.name,
group_concat(g.name) as groups
FROM person_group pg, group g, person p
WHERE pg.group_id = g.id AND pg.novel_id = n.id
GROUP BY ng.person_id
So this query gives me data like
id name groups
2345 John Admin, SuperAdmin, RedHat
But the problem is: if that person doesn't belong to any group, the query doesn't return that person!
Any would be appreciated!

Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
That is exactly your problem here. When you are writing more than one table in the FROM clause, you should be thinking "what type of JOIN do I need". If you had that thought, you would immediate realize that you need an outer join to do what you want:
SELECT p.id, p.name, group_concat(g.name) as groups
FROM person p LEFT JOIN
person_group pg
ON pg.person_id = p.id LEFT JOIN
group g
ON pg.group_id = g.id
GROUP BY p.id, p.name;
If you don't know what an outer join is, then that is all the more reason to use the proper, explicit syntax, so you can learn.

Related

How to select all the authors from database with the number of books assigned to them?

I've the following DB structure:
Authors(id,name);
Books(id,title,authorId);
I want to select all fields from authors and the number of books they are assigned to. I've managed to get the result, but only for the authors that are assigned to at least one book, which is not what I want. I tried with the following query:
SELECT books.*,authors.*
FROM authors
FULL OUTER JOIN books
ON authors.id = books.authorId;
but it doesn't work.
I guess that you want a left join and aggregation:
select a.id, a.name, count(*)
from authors a
left join books b on b.authorId = a.id
group by a.id, a.name
outer join will bring back authors without books. Instead use inner join and your results will only bring back authors with at least 1 book.
I would recommend a correlated subquery:
SELECT a.*,
(SELECT COUNT(*)
FROM books b
WHERE a.id = b.authorId
) as num_books
FROM authors;
This allows you to use SELECT a.* from authors. If you put a GROUP BY in the outer query, you either need to list all the columns separately or be using a database that allows you to aggregate by a primary key, while selecting other columns (this is standard functionality but most databases do not support it).
Definitely you need LEFT JOIN and GROUP BY, but details is not clear enough from the task description. Let's try a kind of
SELECT b.*, ab.count
FROM authors AS a
LEFT JOIN (
SELECT authorId, COUNT(*) AS count
FROM books
GROUP BY authorId
) AS ab ON a.id = ab.authorId;
also, if you don't want to get NULL for some authors, you can apply such expression:
IFNULL(ab.count, 0) AS count

Alias not working in query

I need to display the name of the user and their department who has raised the maximum number of queries. I wrote the following query by joining 5 tables; user, query, profile, degree, and department.
The problem is in the result the alias is not being used for the column names. For both the columns it appears as just name
select user.name 'USER_NAME',department.name 'DEPT_NAME'
from user
inner join query on (query.user_id=user.id)
inner join profile on (user.profile_id=profile.id)
inner join degree on (profile.degree_id=degree.id)
inner join department on (degree.department_id=department.id)
group by user.name
order by count(query.id) desc
limit 1
Use 'as' keyword in order to use alias name in mysql and also remove single quotes.
select user.name as USER_NAME from user;
The following syntax work perfectly for me :
select U.name AS "USER_NAME", D.name AS "DEPT_NAME"
from user U
inner join query Q on (Q.user_id=U.id)
inner join profile P on (U.profile_id=P.id)
inner join degree C on (P.degree_id=C.id)
inner join department D on (C.department_id=D.id)
group by U.name
order by count(Q.id) desc
limit 1;
Sometimes, Mysql prefer you pout an alias on your column when you use some JOIN.
Try it this way;
select thisuser.name 'USER_NAME',department.name 'DEPT_NAME'
from user as thisuser
inner join query on (query.user_id=thisuser.id)
inner join profile on (thisuser.profile_id=profile.id)
inner join degree on (profile.degree_id=degree.id)
inner join department on (degree.department_id=department.id)
group by thisuser.name
order by count(query.id) desc
limit 1
but this is not a good practice when constructing a query;
it looks like this
select thisuser.name,thisdept.name from
(select name,user_id from user) as thisuser
inner join
(select name,user_id from department) as thisdept
on thisuser.user_id = thisdept.user_id
Simply remove the quotes from your query and it will work, but you could use the keyword AS to make it clear that you're using an alias.
I would also use lower case aliases in order to avoid confusion with keywords, and also use uppercase for keywords;
SELECT user.name AS user_name, department.name AS dept_name
...

Get users who have same properties (MySql query)

I have 2 tables as shown below and I want to search users who have vehicle "motorbike" AND "car", related to the tables, the search result should show only (1) john , not (3) mark, because I want "AND" not "OR".
How is it done with MySQL query ?
select * from members m left join properties p on m.user_id = p.user_id where concat_ws(',',property,value) in ('vehicle,motorbike','vehicle,car')
try this:
select name from members m, properties p where m.user_id=p.user_id and p.value="moterbike" and p.value="car";
Use the HAVING clause:
SELECT
A.user_id,
name,
property
FROM members A
INNER JOIN properties B
ON A.user_id=B.user_id
WHERE value IN ('motorbike','car')
GROUP BY A.user_id,name,property
HAVING COUNT(A.user_id)<>1
with respect,
I think some time it gives wrong result if we use having example because some time value can have 2 or more cars in same user
join example not retrieving any record
my answer is this
SELECT cc.*,mem.name
FROM
(SELECT user_id
FROM propoties
WHERE value='car') cc
JOIN
(SELECT userid
FROM properties
WHERE value='moterbyke') mb ON cc.userid=mb.userid
JOIN member mem ON cc.memberid=mem.memberid

Need help combining two functional mysql querys into one?

I have this query that will return a list of all of the people associated with Thomas and their ids.
SELECT c.name, c.ID
FROM namesandID s, associations o, namesandID c
WHERE s.name='Thomas' AND o.id = s.ID AND o.associateID = c.ID
GROUP BY c.ID;
Then I have this query that I can manually type in the id number and it will return the correct count of associates.
SELECT count(*) FROM (
SELECT associateID FROM associations WHERE id=18827 GROUP BY associateID
) AS t;
My goal is to have one query that will take Thomas as the name and return three columns that will have his associate their id number an the number of people they are associated with.
Also as some additional information this is a very large database with about 4million rows and 300million associations so any speed increase on either of these queries would be greatly welcomed.
Not tested, however the below should work:
select
c.name,
c.id,
assoc_count.cnt
from
namesandIds s
inner join
associations o on
o.id = s.ID
inner join
namesandId c on
c.ID = o.associateId
left outer join
(
select
id,
count(distinct associateId) as cnt
from
associations
group by
id
) assoc_count on
assoc_count.id = c.ID
where
s.name = 'Thomas'
Not very efficient but
SELECT c.name, c.ID, COUNT(DISTINCT o.associateID)
FROM {the rest of the first query}
should do the trick.

How do I finish of this SQL query

It works but what I would like is to list username, first name, last name not all but I've tried JOIN and isn't seeming to work. Any ideas? Thanks!
MY DB:
http://gyazo.com/eb13cd68440d20719ce0783018cb9828
SELECT
M.Username,
M.first_name,
M.Last_name,
COUNT(1) AS num_comments
FROM members AS M
INNER JOIN comments AS C
ON C.memberID = M.memberID
GROUP BY
C.memberID
ORDER BY COUNT(1) DESC
LIMIT 1
This matches the Member to all their comments, groups by the member to get the count of comments for the users, orders by the count starting highest first, then returns the first result.
Instead of selecting * (ALL) just use SELECT table.username, table.firstname, table.lastname [...].
You can leave out the table. if all information is stored in your comments table. If not, adjust accordingly. In that case you'll also need to Join the comments table with the table where the rest of the information is stored.
Edit:
SELECT m.username, m.first_name, m.last_name FROM members m, comments c WHERE m.MemberID = c.MemberID AND c.author = (select max(author) from comments)