SQL Count subcategories - mysql

I am trying to figure out how to use the count function in order to count how many subcategories each of my categories have.
My original query is as follows(where name = the category name):
select
catid,
name,
pcatid
from category
I simply want to add a column (which is not included in my DB anywhere) called 'SubCategoryCount'. This column will count for each catid how many times it is being referenced my the pcatid column, if that makes sense.
A simple example DB would be
catid name pcatid
1 Base NULL
2 Computers 1
3 Phones 1
4 Laptops 2
5 Dell 4
And i would like to produce
catid name pcatid SubCategoryCount
1 Base NULL 2
2 Computers 1 1
3 Phones 1 0
4 Laptops 2 1
5 Dell 4 0
But how would i achive this?
Thanks for your help
John

You need to join the table itself using LEFT JOIN so it will display all records in the table even if it does not have subcategory.
SELECT a.catid,
a.NAME,
a.pcatid,
COUNT(b.pcatid) SubCategoryCount
FROM category a
LEFT JOIN category b
ON a.catid = b.pcatid
GROUP BY a.catid, a.NAME, a.pcatid
SQLFiddle Demo
PS: This query is just a projection of result without changing the original schema of the table. it doesn't physically add new column on table category.

Related

Select from two tables mysql in a particular order because the output must have a particular structure

I have a unique situation where I have to select particular columns from two tables in a particular order. Below is the table for the vendors
vid
company
mno
phone
1
Xoxoxo
MTN
2459999999
2
Vovovo
MTN
2459998888
3
Yrewmi
Vodafone
2459997777
Here is the order_content table.
oid
vendor_id
amount
2
2
2
2
1
4
2
1
7
3
1
1
I want to select the vendor.company, vendor.mno, SUM(order_content.amount), vendor.phone for a particular ordercontent.oid selecting only vendors involved. I want to get the vendors details from the vendor table and sum up the amount for a particular order. Lets say order 2 that is old = 2.
SELECT DISTINCT vendor.company AS customerName, vendor.mno, SUM(orders_content.price) AS amount
FROM orders_content, vendor
WHERE orders_content.oid = 2
GROUP BY orders_content.oid;
The result I am expecting
customerName
mno
amount
phone
description
reference
Vooxoo
MTN
2
2459998888
orders
154013949
Xoxoxo
MTN
11
2459999999
orders
78793949
You need to specify a joining condition between the tables, and group by vid, not oid. You don't need to group by oid since the WHERE clause restricts to a single order.
SELECT vendor.company AS customerName, vendor.mno, SUM(orders_content.price) AS amount
FROM vendor
JOIN orders_content ON orders_content.vendor_id = vendor.vid
WHERE orders_content.oid = 2
GROUP BY vendor.vid

How to create a new column in output and give values using join in MySQL

I have two tables 'group' and 'prize' where I have id, mem_id, membername in group table and id, prize_memid, prized_memname in prize table.
***group table***
id mem_id membername
1 1 A
2 1 A
3 2 B
4 3 C
5 3 C
***prize table***
id prize_memid prized_memname
1 1 A
2 32 yy
3 20 ww
4 2 B
I want my result like this using JOINS (membership is extra column, that is not in table)
***Output***
mem_id membername membership
1 A Prized
2 B Prized
3 c Non-Prized
Group By on mem_id and member_name. Do Left join starting from group table to prize table on mem_id. Left join will allow us to consider all the members, whether they have been given a prize or not.
Note that group is a Reserved keyword in MySQL. You should really considering renaming your table to something else. Otherwise, you will have to use backticks around it.
Now, use Conditional functions like If() to check if a particular has prize or not (COUNT(prize_memid) should be greater than zero, if he has been given a prize atleast once).
Try the following:
SELECT
g.mem_id,
g.membername,
IF(COUNT(p.prize_memid) > 0, 'Prized', 'Non-Prized') AS membership
FROM
`group` as g
LEFT JOIN `prize` as p ON p.prize_memid = g.mem_id
GROUP BY g.mem_id, g.membername

MySQL: AVG when there are no matching rows

I'm creating a website where users can rate items (say books), from 1 to 5 stars. I have created a MySQL database and a table which stores info about each rating (itemid, userid, ratingValue).
Each item has a dedicated webpage, and I'd like to put on this page info about: (1) number of ratings and (2) average rating. I thought that this was best done with a view. In thinking about MySQL queries to use in the view, I came to:
SELECT ItemID, COUNT(ratingValue), IFNULL(AVG(ratingValue),0) FROM reviews GROUP BY ItemID
Problem: if an item is not yet rated, it will not appear on the query. What I would like is that all items appear in the query result (view), and if there is an item with no reviews, it should appear with the information that there are 0 reviews and that the average rating is some arbitrary value, let's say 0.
From the official documentation,
AVG() returns NULL if there were no matching rows
and for that reason I tried to use the IFNULL() function. However, it doesn't work. For example, in a database with items 1,2,3,4,5, where item 5 has no reviews, I'll get:
ItemID COUNT(Rating) IFNULL(AVG(ratingValue),0)
1 4 4.0000
2 2 4.0000
3 2 3.5000
4 3 5.0000
Any ideas on how to overcome this problem?
You would have to have another table that lists all of your items (without regard to whether they have reviews) and left join that table to your reviews table. Without that, there is no way to infer from the reviews table alone which items may exist that have no reviews.
So something like:
SELECT
i.itemID AS itemID,
COUNT(r.rating) AS ratingCount,
AVG(ratingValue) AS averageRating
FROM items AS i
LEFT JOIN reviews AS r
ON i.itemID = r.itemID
GROUP BY i.itemID
This should give results like:
ItemID ratingCount averageRating
1 4 4.0000
2 2 4.0000
3 2 3.5000
4 3 5.0000
5 0 NULL

Count Category products with mysql

I have to count products inside each category like I have a category A that have two childs B and C.
In B category have 10 products and C category have 5 Products.
I want to write a query that count product like A = 15 B = 10 C = 5.
I have wrote a query that count only for child categories.
My query is given below
SELECT
c.`id`,
c.`parent_id`,
c.`name`,
c.`slug`,
c.`route_id`,
c.`description`,
c.`excerpt`,
c.`sequence`,
c.`image`,
c.`seo_title`,
c.`meta`,
c.`enabled`,
(SELECT
COUNT(`product_id`)
FROM
HM_category_products
WHERE
HM_category_products.category_id IN (SELECT
HM_categories.`id`
FROM
HM_categories
WHERE
(id = c.`id` OR id = c.`parent_id`))) AS count
FROM
`HM_categories` AS c
EDITED :- Below is my tables structure. This is just an example.
Category Table
id parent_id name slug enabled
1 0 Mobiles & Tablets mobiles-tablets 1
2 1 Mobile Phones mobile-phones 1
3 1 Tablets tablets 1
4 1 Mobile Accessories mobile-accessories 1
5 0 Electronics & Computers electronics-computers 1
6 5 Cameras & Accessories cameras-accessories 1
7 5 TV - Video - Audio tv-video-audio 1
Category Product Table
product_id category_id
1 2
2 2
3 2
4 2
5 3
6 2
7 3
8 3
9 3
10 2
11 3
12 2
13 2
14 2
15 2
You hav to use the "Group by" with something like:
SELECT
category_id, COUNT(*)
FROM
HM_category_products
GROUP BY category_id
This would get your table HM_category_products Grouped by category_id so will know how mane rows of each category its in the table, whats mean you will know the number of product of each category. Then you can join this resulting table with category one to get the category info. (Sorry for my english)
The GROUP BY statement is used in conjunction with the aggregate
functions to group the result-set by one or more columns. SQL GROUP BY Statement
for more info abaut "Group by" read
12.16.2 GROUP BY Modifiers and
12.16.1 GROUP BY (Aggregate) Functions
EDIT: I see now what you whant. I already give you the direction but here its a step furder: DISCLAIMER: THIS QUERY ITS JUST EXAMPLE, IT DOSNT WORK
CREATE VIEW view_2 AS
SELECT
category_id, COUNT(*) AS product_sum
FROM
HM_category_products
GROUP BY category_id
CREATE VIEW view_1 AS
SELECT
*
FROM
HM_categories
LEFT JOIN
view_2 AS a ON HM_categories.id = a.category_id;
SELECT
id,
name,
(SELECT
SUM(product_sum)
FROM
view_1
WHERE
parent_id = final.id) as product_count
FROM
HM_categories AS final;
that way you will get the product of a parent category, your only missing a CASE on the last select "product_count" to the child categorys, but that sum its easy because you already hav it on the view_1 (again sorry for my english)

MySQL order by points from 2nd table

So I have MySQL 3 tables, items (which in this case are lodging properties and the data is simplified below), amenities that the properties might offer, and amenities_index which is a list of item ids and amenity ids for each amenity offered. The end user can select any number of amenities they want and I want to return the results in order of the number of amenities that match what they are looking for. So, if they search for 3 different amenities, I want the items listed that offer all 3, then those that offer 2, 1 and finally the rest of the items. I have a query that I think is working for getting the results in the correct order, but I was hoping that I could also return a point value based on the matches, and that's where I'm running into trouble. My SQL skills are a bit lacking when it comes to more complex queries.
Here is an example query I have that returns the results in the correct order:
SELECT * FROM items
ORDER BY
(
SELECT count(*) AS points
FROM `amenities_index`
WHERE
(amenity_id = 1 || amenity_id = 2)
AND amenities_index.item_id = items.id
) DESC
And here is what the tables are structured like. Any help is appreciated.
items table
id name
1 location 1
2 location 2
3 location 3
4 location 4
amenities table
id name
1 fireplace
2 television
3 handicapped accessible
4 kitchenette
5 phone
amenities_index
item_id amenity_id
1 2
1 3
1 5
2 1
2 2
2 6
3 2
3 3
3 4
3 5
You want to move your expression into the select clause:
SELECT i.*,
(SELECT count(*) AS points
FROM `amenities_index` ai
WHERE amenity_id in (1, 2) AND
ai.item_id = i.id
) as points
FROM items i
ORDER BY points desc;
You can also do this as a join query with aggregation:
SELECT i.*, ai.points
FROM items i join
(select ai.item_id, count(*) as points
from amenities_index ai
where amenity_id in (1, 2)
) ai
on ai.item_id = i.id
ORDER BY ai.points desc;
In most databases, I would prefer this version over the first one. However, MySQL would allow the first in a view but not the second, so it has some strange limitations under some circumstances.