count number of foreign keys - mysql

i have three tables.
1.fi_category
+----+-----------------+-----------------+
| id | name | slug |
+----+-----------------+-----------------+
2.fi_subcategory
+----+-----------------+-----------------+-------------+
| id | name | slug | category_id |
+----+-----------------+-----------------+-------------+
3.fi_business_subcategory
+----+-------------+----------------+
| id | business_id | subcategory_id |
+----+-------------+----------------+
what i am basically trying to do is,
fetch all categories
fetch all subcategories that belong to categories.
count the number of business that exist for particular subcategory.
this is what i tried doing.
SELECT
f.id,
f.name,
f.slug,
f2.id,
f2.name,
f2.slug,
COUNT(f3.business_id) as count
FROM
fi_category f
LEFT JOIN
fi_subcategory f2 ON f.id = f2.category_id
LEFT JOIN
fi_business_subcategory f3 ON f2.id = f3.subcategory_id
however the above query fetches only 1 record. how do i fetch what i want?

I would add a GROUP BY clause:
SELECT
f.id,
f.name,
f.slug,
f2.id,
f2.name,
f2.slug,
COUNT(f3.business_id) as count
FROM fi_category f
LEFT JOIN fi_subcategory f2
ON f.id = f2.category_id
LEFT JOIN fi_business_subcategory f3
ON f2.id = f3.subcategory_id
GROUP BY f.id,
f.name,
f.slug,
f2.id,
f2.name,
f2.slug
Or get your count() in a sub-query:
SELECT f.id,
f.name,
f.slug,
f2.id,
f2.name,
f2.slug,
f3.cnt
FROM fi_category f
LEFT JOIN fi_subcategory f2
ON f.id = f2.category_id
LEFT JOIN
(
select count(business_id) cnt, subcategory_id
from fi_business_subcategory
group by subcategory_id
) f3
ON f2.id = f3.subcategory_id

Related

Counting rows when groupBy by several fields

I have follow query
Select parent.*,
( Select ?????????
from event e
where e.company_id = parent.company_id
AND e.event_type_id in (10, 11, 12)
AND
e.email in
(Select DISTINCT u.email
from users u where u.parent_id = parent.id )
and e.subject_id in
(Select DISTINCT s.subject_id from subjects s where s.parent_id = parent.id )
GROUP by e.email, e.subject_id ) as done
from parent_table parent
I need put something instead ???????? to count subquery rows
I tried to wrap it with another subquery
Select count(*) from (.........)
but in this case my inner query not see parent table
Unknown column 'parent.company_id' in 'where clause'
subquery itself returns table like
----------------------------------------
| email | subject | count |
----------------------------------------
| email1 | 1 | 1 |
| email2 | 5 | 3 |
| email3 | 20 | 22 |
so its events count by email-subject pairs
on top level I need just number of such pairs
UPDT:
seems
COUNT(DISTINCT e.email, e.subject_id)
instead
GROUP by e.email, e.subject_id )
works fine for me
( Select COUNT(DISTINCT e.email, e.subject_id)
from event e
where e.company_id = parent.company_id
AND e.event_type_id in (10, 11, 12)
AND
e.email in
(Select DISTINCT u.email
from users u where u.parent_id = parent.id )
and e.subject_id in
(Select DISTINCT s.subject_id from subjects s where s.parent_id = parent.id ) ) as done
from parent_table parent

select and count rows

I have 2 tables and I need to select and count rows in one query, maybe somebody can help me with that, my query is:
SELECT
c.id, c.first_name, c.last_name, c.speciality, c.level, c.email, c.skype, c.city,
s.status_type, c.status_id, c.linkedin, c.link_cv, c.interview_res, c.createdAt,
c.updatedAt, c.recruiter_id, u.first_name AS fname, u.last_name AS lname
FROM
Candidates c
JOIN Users u
ON c.recruiter_id = u.id
JOIN Statuses s
ON s.id = c.status_id
WHERE
c.deleted = false
and I need to get count of the rows that respond my select and count them.
example output (what I want):
count | fname | lname | ..... |
---------------------------------
3 | Ihor | Shmidt | ... |
3 | Andre | Agassi | .... |
3 | Roger | Federer| ..... |
i.e. I want to have my fields that I select and their count
Before the "from" portion of the query, please add count (*). It will give you the count of the rows.
Select ......, count (*) from Candidates c
JOIN Users u ON c.recruiter_id = u.id
JOIN Statuses s on s.id = c.status_id
WHERE c.deleted = false;
COUNT(*) as count or COUNT(c.id) as count
SELECT COUNT(*) as count,c.id, c.first_name, c.last_name, c.speciality, c.level, c.email,
c.skype, c.city, s.status_type, c.status_id, c.linkedin, c.link_cv, c.interview_res,
c.createdAt, c.updatedAt, c.recruiter_id, u.first_name AS fname, u.last_name AS lname
FROM Candidates c
JOIN Users u
ON c.recruiter_id = u.id
JOIN Statuses s
ON s.id = c.status_id
WHERE c.deleted = false;
SELECT c.id, ( SELECT COUNT(*) FROM Candidates c
JOIN Users u ON c.recruiter_id = u.id
JOIN Statuses s ON s.id = c.status_id
WHERE c.deleted = false ) AS count FROM Candidates
c JOIN Users u ON c.recruiter_id = u.id
JOIN Statuses s ON s.id = c.status_id
WHERE c.deleted = false ;

Mysql GROUPing with ORDER based on auto increment column

I have to group my anime index according to their AniDB ID and show the values in a DESCENDING order according to file auto increment id.
Here's what I did currently:
SELECT
f.id, f.category, f.anidb, f.mal_id, COUNT( * ) AS dupes, f.filename,
a.titles, a.synopsis, a.episodes, a.image, a.rating,
c.name as cat_name, c.id as categoryid
FROM table_files f
LEFT JOIN table_anidb a ON a.id = f.anidb
LEFT JOIN table_categories c ON c.id = f.category
GROUP BY a.id ORDER BY f.id DESC
PROBLEM:
I have Naruto 8 episodes. episode 8's ID is 204. And ep.1 has ID 160. The query return like this:
id | anidb | filename | dupes | cat_name
--------------------------------------------------------
201 | 8692 | SAO | 1 | Series
200 | 9251 | RYO | 1 | Movie
.....
.......
160 | 239 | Naruto ep.1 | 8 | Series
But I want Naruto Episode 8 to be showed in the top of the results instead of episode 1 in the last.
How do I group by anidb and mal_id at the same time with an OR logic? So that the grouping can be done even if there is not any anidb ID provided.
Ad. 1.
Since id, anidb and filename are all in one table i'm afraid you can't get away from doing a subquery join:
SQLFiddle
SELECT f.id, f.anidb, f.filename
FROM files f
JOIN
(SELECT MAX(id) as id FROM files GROUP BY anidb) AS f2
ON f2.id = f.id
ORDER BY f.id DESC
(data flattened for the sake of readibility but you can get the general idea)
Ad. 2.
As for the second problem, you really just have to add second grouping column to the above joined subquery:
SQLFiddle
SELECT f.id, f.anidb, f.mal_id, f.filename
FROM files f
JOIN
(SELECT MAX(id) as id FROM files GROUP BY anidb, mal_id) AS f2 on f2.id = f.id
ORDER BY f.id DESC
The NULL's are distinct from each other (e.g. NULL != NULL) so there's no fear that grouping would melt all the nulled anidb rows into one.
For the first problem you can use ORDER BY dupes
SELECT
f.id, f.category, f.anidb, f.mal_id, COUNT( * ) AS dupes, f.filename,
a.titles, a.synopsis, a.episodes, a.image, a.rating,
c.name as cat_name, c.id as categoryid
FROM table_files f
LEFT JOIN table_anidb a ON a.id = f.anidb
LEFT JOIN table_categories c ON c.id = f.category
GROUP BY a.id ORDER BY dupes DESC
For the second problem you can use CASE to check if f.anidb is null
SELECT
f.id, f.category, f.anidb, f.mal_id, COUNT( * ) AS dupes, f.filename,
a.titles, a.synopsis, a.episodes, a.image, a.rating,
c.name as cat_name, c.id as categoryid
FROM table_files f
LEFT JOIN table_anidb a ON a.id = f.anidb
LEFT JOIN table_categories c ON c.id = f.category
GROUP BY
(CASE WHEN f.anidb IS NULL THEN f.mal_id ELSE f.anidb END )
ORDER BY dupes DESC

mysql mixing counts from several tables

I am trying to achieve total number of topics, total number of posts, and last post for given section, please find db structures and query as following...
fcats
| id | title | section |
+----+--------+---------+
| 1 | test | gd |
+----+--------+---------+
ftopics
| id | title | cat_id |
+----+--------+---------+
| 1 | test1 | 1 |
+----+--------+---------+
fposts
| id | post | topic_id | posted_by
+----+-------+----------+---------+
| 1 | post | 1 | user |
+----+-------+----------+---------+
current query
SELECT id,
title ,
(SELECT count(id)
FROM ftopics
WHERE cat_id = id) AS total_topics
FROM fcats
WHERE section = "gd"
by using above query, i could only get total_topics for given section, but i am confused about how to get total number of posts, and last post for given section. please help, thanks.
SELECT A.id section_id,
IFNULL(COUNT(DISTINCT B.id),0) topics_count,
IFNULL(COUNT(C.id),0) post_count,
(SELECT post from fposts where id = MAX(C.id)) last_post
FROM fsections A LEFT JOIN ftopics B
ON A.id = B.cat_id
LEFT JOIN fposts C
ON C.topic_id = B.id
WHERE A.section = "gd"
GROUP BY A.id
Also include the null case if the section doesnot have any post
Maybe something like this:
SELECT
id,
title ,
(
SELECT
count(ftopics.id)
FROM
ftopics
WHERE
ftopics.cat_id = fcats.id
) AS total_topics,
(
SELECT
COUNT(distinct fposts.id)
FROM
ftopics
JOIN fposts
ON ftopics.id=fposts.topic_id
WHERE
ftopics.cat_id = fcats.id
),
(
select
fposts.id
from fposts
inner join ftopics on fposts.topic_id = ftopics.id
inner join fcats c2 on c2.id = ftopics.cat_id
where fcats.id = c2.id
order by fposts.id desc
limit 1
) as last_post_id
FROM fcats
WHERE section = "gd"
For first part of your answer you should use count distinct, and for second part a subquery:
SELECT c.id,
c.title ,
count( distinct t.cat_id) AS total_topics ,
count( distinct p.id) AS total_posts ,
(select p2.id
from ne_forum_posts p2
inner join ne_forum_topics t2 on p2.topic_id = t2.id
inner join ne_forum_sub_cats c2 on c2.id = t2.cat_id
where c2.id = c.id
order by p2.id desc
limit 1) as last_post_id
FROM ne_forum_sub_cats c LEFT OUTER JOIN
ne_forum_topics t on c.id = t.cat_id LEFT OUTER JOIN
ne_forum_posts p on p.topic_id = t.id
WHERE section = "gd"
all typos fixed and tested.

Counting and Joins

I have a query like this:
SELECT c.id, c.name, f.name
FROM companies c
INNER JOIN facilities f ON c.id = f.company
ORDER BY c.name DESC, f.name
I also want to retrieve a COUNT() of all work_orders (a table) that are approved (a column containing 0 or 1) for each row (each facility).
e.g, SELECT COUNT(*) FROM work_orders w WHERE w.facility = f.id AND w.approved = 1
The result should look like
company | facility | count
--------------------------
goog | ohio | 2
goog | cali | 0
tekk | cupertin | 0
As kind of a follow up, i'd also like to add another count column where w.approved = 0
SELECT c.id, c.name, f.name, COUNT(w.id) AS work_orders
FROM companies c
INNER JOIN facilities f ON c.id = f.company
-- LEFT JOIN used in case there are facilities with no work orders
LEFT JOIN work_orders w ON f.id = w.facility AND w.approved = 1
GROUP BY c.id, c.name, f.name
ORDER BY c.name DESC, f.name
To do multiple counts (approved or not):
SELECT c.id, c.name, f.name,
wapp.wo AS approved_work_orders,
wnapp.wo AS non_approved_work_orders,
FROM companies c
INNER JOIN facilities f ON c.id = f.company
LEFT JOIN (SELECT facility, COUNT(*) AS wo FROM work_orders WHERE approved=1 GROUP BY facility) wapp ON f.id = wapp.facility
LEFT JOIN (SELECT facility, COUNT(*) AS wo FROM work_orders WHERE approved=0 GROUP BY facility) wnapp ON f.id = wnapp.facility
ORDER BY c.name DESC, f.name
It looks like you just need a grouping on c.id and an if statement
SELECT c.id, c.name, f.name, IF(count(0)>0,1,0)
FROM companies c
INNER JOIN facilities f ON c.id = f.company
LEFT JOIN work_orders w ON w.facility = f.id
GROUP BY f.id
ORDER BY c.name DESC, f.name