count number of rows associated with their id in another table - php

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`

Related

get count number of records which respectively exist in another table with null value also

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.

How to formulate the query to join more than one table

MY tables are as follows
users
id name
1 Michael
2 James
3 John
4 Susie
5 Harvey
products
pid name uploader post_id views exclude groupid
1 learn_java 2 1 21 0 1
2 learn_sql 1 2 8 0 2
3 4 GB DDR3 0 3 5 0 3
4 love jacket 2 4 0 0 5
5 1 TB HDD 3 5 12 1 4
6 kill_ants 3 6 5 0 6
7 2 TB HDD 2 7 2 0 4
8 8 GB DDR3 2 8 18 0 3
9 1 GB DDR2 3 9 7 0 3
product_group
gid name category
1 text 1
2 pdf 1
3 ram 2
4 hdd 2
5 leather 0
6 diy 0
product_category
cid name
1 book
2 electronics
/* forgot about comment field*/
comments
comment_id post_id comment
1 1 ...
2 1 ...
3 2 ...
4 2 ...
5 2 ...
6 3 ...
My Goal:
The product table has 4 types of data.
Products with no uploader( uploader = 0 )
Products that are in review( exclude = 1 )
Products that fall under category = 0(poducts.groupid = product_group.gid AND product_group.category = 0 )
Products that are uploaded by an uploader, not in review and not fall under category = 0( uploader != 0, exclude = 1, poducts.groupid = product_group.gid AND product_group.category != 0)
I only have to consider the 4th type of data. I have to exclude the first three types of data. I have to group these data by their uploader. Say, James have uploaded 3 product, Jones have uploaded 2 product and the rest of the user hasn't uploaded anything.
The query should return this
3 James SUM of views of 3 products
2 Jones SUM of views of 2 products
0 user1 0
0 user2 0
....
....
So if I consider the data of my table, I want to get the data in follwing order
product_num users.id users.name total_views
3 2 James 41(21+18+2)
1 3 Jones 7
1 1 Michael 8
0 5 Harvey 0/NULL
0 4 Susie 0/NULL
I came up with this.
SELECT COUNT(pid) as product_num,
SUM(views) as total_views
users.*
FROM users
INNER JOIN products ON products.uploader = users.id
INNER JOIN product_group ON products.groupid = product_group.category
WHERE exclude = 0
AND product_group.category != 0
Which obviously doesn't work as it doesn't include the users, who hasn't uploaded any product. How to make this work to take these users into account?
EDIT:
SELECT COUNT(pid) as product_num,
SUM(views) as total_views
users.*
FROM users
LEFT JOIN products ON products.uploader = users.id
INNER JOIN product_group ON products.groupid = product_group.category
WHERE exclude = 0
AND product_group.category != 0
GROUP BY users.id
ORDER BY product_num
It also doesn't take users with 0 upload.
Second EDIT:
I have added a comment table(I forgot about it earlier). Is there any way to show the total_number of comments for a user.
Here, James has uploaded product 1, 4, 8. For these post_id is also 1, 4, 8(In real these won't be same). From comments table, these posts have following number of comments 2, 0, 0. So, total number of comment 2.
So, final result should be
product_num users.id users.name total_views total_comments
3 2 James 41(21+18+2) 2
1 3 Jones 7 0/NULL
1 1 Michael 8 3
0 5 Harvey 0/NULL 0/NULL
0 4 Susie 0/NULL 0/NULL
Try this query:
SELECT COUNT(pid) as product_num,
SUM(views) as total_views,
u.*
FROM users u
LEFT JOIN products p
ON p.uploader = u.id
LEFT JOIN product_group pg
ON p.groupid = pg.gid
WHERE p.exclude = 0
AND p.uploader <> 0
AND pg.category != 0
OR p.pid is null
GROUP BY u.id
demo: http://sqlfiddle.com/#!2/c94bef/12
To count a number of comments, please add a dependent subquery to the SELECT clause:
SELECT count(*)
FROM comments c
WHERE c.post_id = p.post_id
in this way:
SELECT COUNT(pid) as product_num,
SUM(views) as total_views,
( SELECT count(*)
FROM comments c
WHERE c.post_id = p.post_id
) As total_comments,
u.*
FROM users u
LEFT JOIN products p
ON p.uploader = u.id
LEFT JOIN product_group pg
ON p.groupid = pg.gid
WHERE p.exclude = 0
AND p.uploader <> 0
AND pg.category != 0
OR p.pid is null
GROUP BY u.id
demo: http://sqlfiddle.com/#!2/5c44f/1

Query and table - MAX and Join

Still very new to all of this so bear with me.
Have 3 tables
table 1: member
Mem_index, Mem_name
1 joe
2 Mark
Table 2: Course
Course_index, Course_Name
1 Math
2 Reading
Table 3 : data
Data index,Member,Course,Score
1 1 1 85
2 1 2 75
3 2 1 95
4 1 2 65
SO what I would like to do is create a table:
Do a query and gather all of the courses, find the max score for each course and attribute the member name to it.
Table result should look like:
Course, Max score,name
Math 95 Mark
Reading 75 Mark
I can do the query individually but unsure of how to loop it and then propogate the data into the table.
How about this query for SQL?
SELECT c.course_name, MAX( d.score ), m.mem_name
FROM members m
JOIN data d on m.mem_id = d.member
JOIN course c on c.course_id = d.course
GROUP BY d.course
ORDER BY d.score, m.mem_name, c.course_name
Not sure if the field names match up but you get the idea - tested this in sql with some dummy data.
Data
Index Member Course Score
1 1 1 60
1 1 1 85
Course
course_id course_name
1 Math
2 English
3 Science
Members
mem_id mem_name
1 Mark
2 James
You will get the following
Course Name Score Member
Math 85 Mark
Try this query :
SELECT c.course_Name , MAX(d.score),m.mem_name
FROM data d
JOIN course c ON d.course=c.course_index
JOIN members m ON m.mem_index = d.member
GROUP BY d.course
ORDER by MAX(d.score) DESC

SUM acorrding to another column

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

Help with limiting a joined mysql database query

I have written a query which returns all records with some many-to-many joins correctly for the entire set or an individual article using WHERE a.id = ?
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id
LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id
LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id
LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
BUT!
I've hit a brick wall trying to work out how to limit the articles to a specific number of IDs, for working with pagination.
I'm ideally trying to use as simple and clear SQL statements as possible because I'm using the codeigniter framework with their active record class.
http://codeigniter.com/user_guide/database/active_record.html
Would really appreciate some help as I don't want to revert to using multiple queries for this as I've tried to reduce it down to a single query for database efficiency.
Have search around and tried some alternatives but nothing seems to work. Many thanks!
For example the results I return are like this
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
2 test 2 2 1 1
2 test 2 1 2 1
2 test 2 1 1 2
2 test 2 5 1 1
2 test 2 8 1 1
2 test 2 1 4 1
2 test 2 1 4 2
I need the results like this so that I can create sub-arrays in the php like this:
$articles = $query->result_array();
$output = array();
foreach ($articles as $article) {
// set up article details
$article_id = $article['id'];
// add article details
$output[$article_id]['article_id'] = $article_id;
$output[$article_id]['date_added'] = $article['date_added'];
$output[$article_id]['title'] = $article['title'];
$output[$article_id]['content'] = $article['content'];
// set up people details and add people array with details if exists
if (isset($article['person_id'])) {
$person_id = $article['person_id'];
$output[$article_id]['people'][$person_id]['person_id'] = $person_id;
$output[$article_id]['people'][$person_id]['lastname'] = $article['lastname'];
$output[$article_id]['people'][$person_id]['firstname'] = $article['firstname'];
}
// set up organizations details and add organizations array with details if exists
if (isset($article['organization_id'])) {
$organization_id = $article['organization_id'];
$output[$article_id]['organizations'][$organization_id]['organization_id'] = $organization_id;
$output[$article_id]['organizations'][$organization_id]['organization_name'] = $article['organization_name'];
}
// set up categories details and add categories array with details if exists
if (isset($article['category_id'])) {
$category_id = $article['category_id'];
$output[$article_id]['categories'][$category_id]['category_id'] = $category_id;
$output[$article_id]['categories'][$category_id]['category_name'] = $article['category_name'];
}
}
But if I just use LIMIT (with offset etc) 1
the results I get are
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
instead of
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
which is my desired result.
OK, so finally I worked out how it is possible.
Thought i'd include it here in case anyone else has the same problem.
Changing this line
FROM articles AS a
to this
FROM (SELECT * FROM articles LIMIT 5,3) AS a
does what I wanted.
So, why don't you use OFFSET 0,10 and LIMIT *number_of_results* in the SQL Query? (if I understood the question)
Specific number of IDs... WHERE ID IN (2,4,6,8)... ?
Are you using codeigniter's pagination?
http://codeigniter.com/user_guide/libraries/pagination.html
You can easily limit the number of records that are being returned using the MySQL LIMIT clause. This can be achieved like the following with your sample query.
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
LIMIT 10
Where 10 is the number of records you wish to display. The MySQL LIMIT clause allows you to specify a limit of the number of records and an initial offset. Like so:
LIMIT <offset>,<limit>
In your case <offset> would be the current page * the number of records on a page. <limit> would be the number of records you would like to display per page.

Categories