Suppose the following situation.
Persons assigned to tasks, and I want to return Person id, Person Name, the number of tasks completed by each person from the following tables.
Table Name - Field Name
Person - id, Name
Task_Person_Combi - Task_id, Person_id
Task* - returns id of Task (actually this is LEFT Joined table which returns id of persons)
(Task has over 100,000 rows, and the query has to be quick well less than 1 second)
After reading MySQL statement combining a join and a count?, I'm trying the following. (but this doesn't seem to work, and I'm kind of lost)
SELECT id, Name,
(
SELECT COUNT(*)
FROM Task_Person_Combi C
WHERE P.id=C.Person_id AND C.Task IN (SELECT id FROM Task* - this is Joined table)
) AS Count
FROM Person P
WHERE id>0
HAVING Count>0
ORDER BY Name
Please help.
Try this?
SELECT id, Name,
COUNT(T.ID) AS TaskCount
FROM Person AS P
INNER JOIN Task_Person_Combi AS C ON P.id=C.Person_id
LEFT JOIN TASK AS T ON C.Task = T.id
WHERE id>0
AND T.id IS NOT NULL
GROUP BY id,Name
HAVING COUNT(T.ID)>0
ORDER BY Name
Related
This is a slight variant of the question I asked here
SQL Query for getting maximum value from a column
I have a Person Table and an Activity Table with the following data
-- PERSON-----
------ACTIVITY------------
I have got this data in the database about users spending time on a particular activity.
I intend to get the data when every user has spent the maximum number of hours.
My Query is
Select p.Id as 'PersonId',
p.Name as 'Name',
act.HoursSpent as 'Hours Spent',
act.Date as 'Date'
From Person p
Left JOIN (Select MAX(HoursSpent), Date from Activity
Group By HoursSpent, Date) act
on act.personId = p.Id
but it is giving me all the rows for Person and not with the Maximum Numbers of Hours Spent.
This should be my result.
You have several issues with your query:
The subquery to get hours is aggregated by date, not person.
You don't have a way to bring in other columns from activity.
You can take this approach -- joins and group by, but it requires two joins:
select p.*, a.* -- the columns you want
from Person p left join
activity a
on a.personId = p.id left join
(select personid, max(HoursSpent) as max_hoursspent
from activity a
group by personid
) ma
on ma.personId = a.personId and
ma.max_hoursspent = a.hoursspent;
Note that this can return duplicates for a given person -- if there are ties for the maximum.
This is written more colloquially using row_number():
select p.*, a.* -- the columns you want
from Person p left join
(select a.*,
row_number() over (partition by a.personid order by a.hoursspent desc) as seqnum
from activity a
) a
on a.personId = p.id and a.seqnum = 1
ma.max_hoursspent = a.hoursspent;
I am trying to optimize a query in Mysql, now this query needs 0,5 seconds and the table only have 2500 rows.
I have 2 tables one table is the tickets and the other the tickets that are grouped.
Tickets:
- ID : Int (Primary Key)
- Name of the ticket: text
GroupTickets:
- ID : Int (Primary Key)
- ID_relation: Int -> the id of the group of the tickets
- ID_Ticket: Int -> the id of the ticket
My query is:
Select T.id, T.name, Count(GP.id_relation)
FROM Tickets as T, GroupTickets as GP
WHERE GP.id_relation IN (
Select id_relation from GroupTickets
Where id_ticket=T.id
)
This select in the where clause make that mysql will do a select by every row so in the future where the table have millions of rows this query will be hard to process.
Am i wrong? Someone know a better way to take this info? I need to know if a ticket is grouped with other tickets in the query.
Best Regards.
Try this (Your query has a redundant IN SELECT ...)
Select T.id, T.name, Count(GP.id) AS RC
FROM Tickets as T
INNER JOIN GroupTickets as GP ON GP.ID_TICKET = T.ID
GROUP BY T.ID, T.name
New version for new question as in comment below:
May be you want something like this:
SELECT A.ID, A.NAME, B.ID_RELATION, C.RC
FROM TICKETS A
INNER JOIN GROUPTICKETS B ON B.ID_TICKET = A.ID
INNER JOIN (SELECT ID_RELATION, COUNT(*) AS RC
FROM GROUPTICKETS A
GROUP BY ID_RELATION) C ON C.ID_RELATION = B.ID_RELATION
;
Could also be useful
CREATE INDEX GROUPTICKETS_IX01 ON GROUPTICKETS(ID_RELATION, ID_TICKET);
I have two tables in my database; groups and members.
groups has the following columns: id, name, description, owner_id, school_id
members has the following columns: id, user_id, group_id
I want to return all the records in group, on each row it should perform a count on the members table to determine how many members each group has.
so my end result should be like this:
id, name, description, owner_id, school_id, count(this is from the members table)
i keep trying but sometimes when i have only 2 groups but 3 members i get 5 rows returned instead of 2.
The standard way to do this is with COUNT(), a LEFT JOIN and a GROUP BY:
SELECT g.*, COUNT(m.id) as member_count
FROM groups g
LEFT JOIN members m
ON m.group_id = g.id
GROUP BY g.id
For performance, ensure you have an index on members.group_id.
The real issue
Involved tables and their columns
accounts [id,name]
rooms [id,name,topic,owner]
room_admins [account_id,room_id]
Q: Get all rooms with their admin- and owner ids.
Where "all" of course has a condition to it (above: WHERE name LIKE ...)
Admins and owners should be returned in one column just called "admins". I tried to concatenate them above into one string.
What I tried
I came up with a solution, but it requires the use of an omnious external variable ":room_id" that changes on each outer SELECT and makes therefore no sense at all.
SELECT id,name,topic,
(SELECT GROUP_CONCAT(admins.account_id) AS owner
FROM
(SELECT account_id
FROM `room_admins`
WHERE room_id=:room_id
UNION
SELECT owner FROM `rooms` WHERE id=:room_id) admins) AS owner
FROM `rooms`
WHERE name LIKE "%htm%" OR topic LIKE "%htm%" LIMIT 20
Well, I haven't given this a deep thought... but I've just came up with this (sample data would have been useful to make tests... so this is just a blind answer).
select id, name, topic, group_concat(owner_admin) from (
select id, name, topic, owner owner_admin from rooms
union
select id, name, topic, account_id from rooms
left join room_admins on id = room_id
) s
where name like "%htm%" or topic like "%htm%"
group by id, name, topic
Basically I'm just generating a derived table with owner and admins mixed in one column. Then performing the grouping on that mixed column.
Most of the times, when you want to select and display dependent data, you want to use a JOIN. In this case, you want to join the rooms with their admins, so basically:
SELECT r.id, r.name, r.topic, a.id
FROM rooms r
LEFT JOIN admins a
ON r.id = a.room_id
WHERE :condition
Since you have one additional admin not in the admins table (the room owner), you have to (self) join a second time:
SELECT r.id, r.name, r.topic, a.id
FROM rooms r
LEFT JOIN admins a
ON r.id = a.room_id
LEFT JOIN rooms o
ON r.id = o.id
WHERE :condition
This doesn't give us any new information, but your question states that you want to return the list of admins in a single field. So, finally, putting it all together:
SELECT r.id, r.name, r.topic, GROUP_CONCAT(a.id)
FROM rooms r
LEFT JOIN
(
SELECT id, room_id FROM admins
UNION SELECT room.owner AS id, rooms.id AS room_id FROM rooms
) a
ON r.id = a.room_id
WHERE :condition
GROUP BY r.id
But to avoid this ugly sub-select-union clause, I'd advise you to put the room owner into your admin table too.
From joining the tables below on the entry.id, I want to extract the rows from the food_brands table which have the highest type_id - so I should be getting the top 3 rows below, with type_id 11940
food_brands
id brand type_id
15375 cesar 11940
15374 brunos 11940
15373 butchers 11940
15372 bakers 11939
15371 asda 11939
15370 aldi 11939
types
id type quantity food_id
11940 comm 53453 10497
11939 comm 999 10496
foods
id frequency entry_id
10497 twice 12230
10496 twice 12230
10495 once 12230
entries
id number
12230 26
My attempt at the query isn't filtering out the lower type.id records - so from the table records below in food_brands, i'm getting those with type_id 11940 and 11939. Grateful for any help fix this!
SELECT fb.*
FROM food_brands fb
INNER JOIN types t ON fb.type_id = t.id
INNER JOIN
(
SELECT MAX(id) AS MaxID
FROM types
GROUP BY id
) t2 ON t.food_id = t2.food_id AND t.id = t2.MaxID
INNER JOIN foods f ON t.food_id = f.id
INNER JOIN entries e ON f.entry_id = e.id
WHERE entries.id = 12230
A simple subquery should do it just fine;
SELECT * FROM food_brands WHERE type_id=
(SELECT MAX(t.id) tid FROM types t
JOIN foods f ON f.id=t.food_id AND f.entry_id=12230)
An SQLfiddle to test with.
If you just want to return the rows from food_brands with the max type id, you should be able to use:
SELECT fb.*
FROM food_brands fb
INNER JOIN
(
select max(id) id
from types
) t
on fb.type_id = t.id
See SQL Fiddle with Demo
I don't know why you are doing all these inner joins after the one on the t2 subquery, since you are only retrieving the columns of fb, but I suppose that you are not showing the whole query, and you just want to get that one fixed.
The issue is actually in the subquery t2: there, for some untold reason, you choose to do a GROUP BY id which changes the MAX function semantic to generate a maximum value per id, and since you are asking the maximum on that very column, MAX and GROUP BY cancel out each other. Just removing the GROUP BY clause fixes the query.
If for some untold reason you cannot remove that clause, perhaps replacing MAX(id) by id and adding ORDER BY id DESC LIMIT 1 would do.
Also, your subquery should probably select also food_id since it is used in the subsequent INNER JOIN clause.