I need to know if there is a possible way doing this with out subquery..
Here is my table structure:
id-name-father_id
1 joe 0
2 mark 0
3 muller 0
4 miki 2
5 timi 2
6 moses 2
7 david 1
8 momo 0
9 daniel 0
10 ermi 3
My table logic is
0 means he is not a child of some one
1+ mean that he is son of man in that row.
Note: if some one have a child, he still
will have 0 in father id (it's mean there is not grand-fathers in my table)
My query is :
SELECT id, name, count(id=father_id) as sons
WHERE father_id = 0
What I want to get is a list of non-children (father_id=0) and sum
the childrens it has.
Is there a way to get the results without a subquery?
This should do it (MySQL):
SELECT `parents`.`id`, `parents`.`name`, COUNT(`children`.*) AS sons
FROM `people` AS parents
LEFT JOIN `people` AS children ON `parents`.`id` = `children`.`father_id`
WHERE `parents`.`father_id` = 0
GROUP BY `parents`.`id`
According to Gary we need to add name to GROUP BY in other SQL databases:
SELECT `parents`.`id`, `parents`.`name`, COUNT(`children`.*) AS sons
FROM `people` AS parents
LEFT JOIN `people` AS children ON `parents`.`id` = `children`.`father_id`
WHERE `parents`.`father_id` = 0
GROUP BY `parents`.`id`, `parents`.`name`
We are joing the table with itself here. So we join all parents with their children.
This will lead to a result like that:
parents.id parents.name children.id children.name
1 joe 7 david
2 mark 4 miki
2 mark 5 timi
2 mark 6 moses
3 muller 10 ermi
8 momo - - # left join allows this line
9 daniel - -
But now we have each parent several times. So we are GROUP'ing the whole thing over the parent’s id, which will result in the following:
parents.id parents.name COUNT(children.*)
1 joe 1
2 mark 3
3 muller 1
8 momo 0
9 daniel 0
You should be able to do it without any joins or sub-queries as follows:
select case father_id when 0 then id else father_id end id,
max(case father_id when 0 then name end) name,
sum(sign(father_id)) sons
from table
group by case father_id when 0 then id else father_id
Related
All data in my tables are in numeric format. For example,
class sex subject medium
5 1 1 1
1 1 1 2
4 3 3 1
5 1 3 2
1 1 3 1
3 1 2 2
1 2 2 2
Other Table contains Description to each value for each table. For Example,
Table Column value text
Student class 1 1ST
Student class 2 2ND
Student class 3 3RD
Student class 4 4TH
Student class 5 5TH
Student sex 1 male
Student sex 2 female
Student sex 3 creator
Student medium 1 English
Student medium 2 Hindi
I am trying to provide a text (label to each column when user queries). I have been able to do it for one column. For example,
SELECT class, sex, avg(total_marks) as total
FROM (
SELECT value, text as sex
FROM Label
WHERE table_name = 'Student' and
Column = 'class' or
) AS Label INNER JOIN Student on value = class
GROUP BY class, sex
This results in
class sex total
1ST 1 64.80
1ST 2 59.66
2ND 1 78.96
2ND 2 96.97
3RD 1 52.67
3RD 2 81.77
4TH 1 61.99
4TH 2 99.78
5TH 1 72.90
5TH 2 70.59
Instead of 1 / 2 /3 in sex I want to show male, female and creator. Select and Group by columns can be more than 4 at times. I am using MySql and PHP Laravel to do this.
I guess I found the answer. Any suggestions are most welcome.
SELECT T1.class, T2.sex, SUM(weight)
FROM household_characteristics
INNER JOIN (SELECT value_label_name as code, value_label_value FROM labels
WHERE table_name = 'Student' and columns = 'class' ) AS T1 ON T1.code = Student.class
INNER JOIN (SELECT value_label_name as code, value_label_value FROM labels
WHERE table_name = 'Student' and columns = 'sex' ) AS T2 ON T2.code = Student.sex
GROUP BY class, sex
Im trying to select every lasted insert row with a match_id and show all match_id's on a php page, but not show multiple rows on same match_id.
Since it is a logging page for my kids football games i will insert multiple rows on same match_id to mark if he scores, so i wont be updating same match_id.
Here you can see a example how the database looks. I have some more columns also but just to get you the idea how it looks.
(AI)id match_id team1 team2 result1 result2 goal timenow
1 1 US ENG 0 0 0 00:00
2 1 US ENG 1 0 0 08:00
3 1 US ENG 1 1 0 13:00
4 1 US ENG 2 1 1 20:00
5 2 US FRA 0 0 0 00:00
6 2 US FRA 1 0 1 04:00
7 2 US FRA 1 1 0 26:00
8 3 US GER 0 0 0 00:00
9 3 US GER 1 0 0 16:00
The result i would like to get is a php page that lists just the last row of every unique match id.
Example html/php would show lika below:
US-ENG 2-1
US-FRA 1-1
US-GER 1-0
Hope you understands what i mean :)
EDIT: got it working by this line of code if somebody other have the same needs.
Thanks to Akilan who lead me in right direction :)
SELECT * FROM table WHERE id IN (SELECT MAX( id ) FROM table GROUP BY match_id) ORDER BY `table`.`timenow` DESC
You can do a order by with time and group by your match id can achieve the desired output right??
For example,
SELECT * FROM match_table GROUP BY match_id ORDER BY TIME(timenow)
Happy Coding,
AK
This will help you
select group_concat(team1,'-',team2,' ',result1,'-',result2) from match_table group by match_id order by match_id DESC LIMIT 1;
SELECT group_concat(t1.team1,'-',t1.team2,' ',t1.result1,'-',t1.result2) from table t1
LEFT JOIN table t2
ON (t1.matchid = t2.matchid AND t1.id < t2.id)
WHERE t2.id IS NULL;
Hi We have 3 Table of a music which is something like this in MySql :
1st Table :
the first table is for playlist table where music playlist is exist.
playlistId playlistTitle categoryId
1 hello 0
2 wow 0
3 wi-fi 0
4 awesome 0
5 sixer 1
6 four 1
7 boundary 2
2nd Table :
2nd table is for songRelation table where every playlist is associated with thier song
playlistId songId
1 4
1 3
1 43
1 57
1 98
2 56
2 67
2 90
2 78
3 98
3 78
3 89
43 90
3rd Table : the 3rd table is for song table where song detail exist
songId songTitle
4 hello
3 real hero
43 singalone
57 awesom
98 really
78 sakaka
98 shikwa
89 moha
90 hello2
67 Sneh
actually i am fetching the result something like this:
playlistId songId categoryId songTitle
1 4 0 hello
1 3 0 real hero
2 56 0 singalone
2 67 0 Sneh
3 78 0 sakaka
3 98 0 Shikwa
where the every playlistId will be with their first 2songIdand with theircategoryIdand also withsongTitle`.
but i want to count the total song with every playlistId
after getting the total song result i want will be something like this :
playlistId songId categoryId songTitle totalSong
1 4 0 hello 5
1 3 0 real hero 5
2 56 0 singalone 4
2 67 0 Sneh 4
3 78 0 sakaka 3
3 98 0 Shikwa 3
here is the jsfiddle Demo where query is without totalSong http://sqlfiddle.com/#!9/7eda7/5
What subquery will be added to get the above desired result.
To get exactly the result you asked, use this:
select p.playlistId,
s.songId,
p.categoryId,
s.songTitle,
(select count(*) from songRelation where playlistId = p.playlistId) totalSong
from playlist p
inner join songRelation r on p.playlistId = r.playlistId
inner join song s on r.songId = s.songId
Using a group by on the main query would merge the detailed song data, forcing you to run two queries: one for details (first 4 fields) and a second query, to recover the totals (last column). Using this solution, you get all detailed data and totals, the sub-query will recover the count of songs for each playlist, the way you asked.
UPDATE:
This way, suggested by rlanvin, should make the query faster, because instead on computing the subquery for each row, it gets computed only once, and then is joined to the main query. The result is the same:
select p.playlistId,
s.songId,
p.categoryId,
s.songTitle,
r1.totalSong
from playlist p
inner join songRelation r on p.playlistId = r.playlistId
inner join song s on r.songId = s.songId
inner join (SELECT playlistid, COUNT(songId) as totalSong from songRelation group by playlistid) r1 on p.playlistId = r1.playlistId
I have added this query to ur SQLFIDDLE.
SELECT p.playlistId, s.songId, p.categoryId, s.songTitle,
(select count(sr1.songId) from songRelation sr1
where sr1.playlistid=p.playlistid
group by sr1.playlistId) as total,
#r := IF (#pid = p.playlistId,
IF (#pid := p.playlistId, #r+1, #r+1),
IF (#pid := p.playlistId, 1, 1)) AS rn
FROM playlist AS p
CROSS JOIN (SELECT #r:=0, #pid:=0) AS vars
INNER JOIN songRelation AS sr ON p.playlistId = sr.playlistId
INNER JOIN song AS s ON sr.songid = s.songid
ORDER BY p.playlistId, s.songId ) AS t
WHERE t.rn <= 2
It is giving the required output. Check the Demo Here
Using Group Functions you can do this:
SELECT `playlistid`, COUNT(`songid`)
FROM `playlist`
GROUP BY `playlistid`
i have two tables. 'listing_messages' and 'listing_message_history'.
listing_messages
=============
message_id listing_id listing_user third_party_user
1 162 7 32
2 162 7 33
3 162 7 12
listing_message_history
======================
listing_message_history message_id is_checked
1 1 0
2 1 1
3 1 1
4 2 0
5 2 1
6 3 0
Search criteria==> listing_user=7, is_checked=1
I want result..
message_id count_of_unread_message_history
12
2 1
3 0
I have made a query is
SELECT count(`lmh`.`message_history_id`) AS COUNT,
`lmh`.`message_id`
FROM `listing_message_history` AS `lmh`
LEFT JOIN `listing_messages` AS `lm` ON `lmh`.`message_id` = `lm`.`message_id`
WHERE `lm`.`third_party_user`=7
AND `lmh`.is_checked=1
GROUP BY `lm`.`message_id`
but it does not returns message_id with count = 0 which message_id do not have is_checked=1
In general, when you use left join, filter conditions on the second table should go in the on clause not the where clause. Try this:
SELECT count(`lmh`.`message_history_id`) AS COUNT,
`lmh`.`message_id`
FROM `listing_message_history` `lmh` LEFT JOIN
`listing_messages` `lm`
ON `lmh`.`message_id` = `lm`.`message_id` AND
`lm`.`third_party_user` = 7
WHERE `lmh`.is_checked = 1
GROUP BY `lmh`.`message_id`;
In addition, you should use the first table for the group by, not the second table.
I have a table where the data are as follow
ID Classroom Person
1 1 Alfred
2 1 Maria
3 2 Maria
4 2 Zoe
5 2 Alfred
6 3 Nick
7 3 Paul
8 3 Mike
9 3 Alfred
10 4 Zoe
11 4 Maria
I want to select and return only the Classroom that has as Person only 'Alfred' and 'Maria'
Following statement :
Select * from table_name where (Person='maria') and (Person=Alfred')
doesn't seem to work.
You can see a SQL Fiddle here,
You can use group by and having:
select classroom
from table t
group by classroom
having count(*) = 2 and
sum(person in ('maria', 'Alfred')) = 2;
This assumes that one person cannot be in a classroom multiple times.
This checks that there are two names in the classroom and they are for the two names of interest. If you can have duplicates, you would want:
having count(distinct name) = 2 and
count(distinct case when person in ('maria', 'Alfred') then person end) = 2;
Try this. Group by and having with Count should work.
SELECT Classroom
FROM tablename
WHERE Person IN( 'maria', 'Alfred' )
GROUP BY classroom
HAVING Count(Person) = 2