Counting distinct items within a category on SQL - php

I need to compose a SQL statement as follows:
I have a table with many items, each item having a category. In total there are 3 categories.
I need to select the DISTINCT categories and then order them by number of items within each category.
Would this be a good way? Or too slow?
SELECT DISTINCT category, count(*) AS counter
FROM item_descr
GROUP BY category
ORDER BY counter DESC

The DISTINCT is not needed since you are using GROUP BY category:
SELECT category, count(*) AS counter
FROM item_descr
GROUP BY category
ORDER BY counter DESC

The GROUP BY is doing what you want. DISTINCT is redundant.

It is very important to have an index on category if you want good performance especially on larger tables.

Related

MySQL, how to sort according to categories?

I know how to select and sort one category separately and how to select and sort all categories according to ASC or DESC. My question is how to select all categories and sort them in the way that for instance fifth category will be on first place and others behind it?
Presuming that fifth category just means that you want to prefer a specific category like Category-Name, you can use CASE:
SELECT t.*
FROM dbo.Tablename t
ORDER BY CASE WHEN t.Category = 'Category-Name' THEN 0 ELSE 1 END ASC,
Category ASC
You can use field() function
select *
from categories
order by field(id,5) desc,id
or
select *
from categories
order by id= 5 desc,id

SQL: How to sort by sum of fields where certain conditions are met?

I have a shop that sells items
Every time an item is sold, following data is placed in a database:
-item_id
-item_count
-bought_value (money spent to buy this item, taking amount into consideration)
Now I would like to know the percentage of money that has come in PER ITEM
I would like to have this information sorted but I'm not fully sure how to do this
What I currently have is:
to find total money that has come in: SUM(boughtvalue)
to find all items: SELECT DISTINCT item_id
iterate through all items and use: SELECT SUM(boughtvalue) WHERE item_id = ...
This gets me the results, but they're not sorted this way
What I'm looking for is something like "SELECT DISTINCT item_id ORDER BY SUM(boughtvalue)"
My PHP script that finds this information currently displays something like this:
15332-0.75640207175834%
18353-0.30683127676158%
18349-0.53882565675204%
18351-0.20954331095913%
All I need is to have this information sorted.
You are looking for group by:
SELECT item_id, SUM(boughtvalue)
FROM table t
GROUP BY item_id
ORDER BY SUM(boughtvalue) DESC;
Try something like:
select item_id, sum(item_count), sum(bought_value) from item_table group by item_id
assuming your table name is item_table
Play around with something like this
SELECT item_id,
(
SUM( boughtvalue ) / ( SELECT SUM(boughtvalue) from tbl )
) as percentvalue
FROM tbl
GROUP BY item_id
ORDER BY percentvalue DESC;
Ususally I discourage subqueries, but I think the optimizer will optimize that away.
Try:
SELECT item_id, SUM(bought_value) as bought_value FROM item_table GROUP BY item_id ORDER BY bought_value

MySQL. Need to count number of posts in ~9000 categories

I'm making a sitemap. I have a table, which connects posts with categories (2 columns: categoryId, postId). There are nearly 9000 categories in total, and I want to count number of posts in each category to predict number of pages in pagination. I tried to do 9000 COUNT(*)'s for each category, but that is too slow (2 hours, actually). What can I do? Thanks.
Use the GROUP BY function
SELECT C, COUNT(*)
FROM TABLE
GROUP BY categoryId as C
You just have to do a SELECT COUNT and GROUP it by your categoryid like this :
SELECT C, COUNT(*) FROM yourtable GROUP BY categoryId as C
If you want only for a specific category, try to use WHERE categoryID = ?
before the GROUP BY
You can count it and group it by CategoryID simple as that
select Count(postid) as NumberOfPosts, categoryid from your_table group by categoryid
and that is simple as that.
Best solution for you is to create table where you will hold real statistic and increase it when post is created or decrease it when post is deleted.
NEW
if you want for certain category then just add to query where categoryid=?
so your query should look like
select Count(postid) as NumberOfPosts from your_table where categoryid=?
or if you want to do search for more than one category than just do this
select Count(postid) as NumberOfPosts, categoryid from your_table where categoryid in (1,2,3,4)
group by categoryid

SQL Select multiple matching rows

I have a SQL database of products from different suppliers, so the same product could appear multiple times with different prices.
Is it possible to select all of the products that have more than 4 prices, so bascially all of the rows which have more than 4 rows with the same ID?
You could add COUNT(*) AS number_of_products to SELECT, GROUP BY product_id, then use HAVING number_of_products > 4.
Note that HAVING is applied on the results (it basically goes through all the results, one by one, and applies the conditions), so it will be slower than WHERE. If you have hundreds of thousands of rows and you need performance, consider pre-counting the products, storing the indexed count value somewhere, then using a simple WHERE instead.
Yes, GROUP on the identificator for your item, and specify the number of prices to count in a HAVING clause, something like this :
SELECT ItemID, COUNT(Price) FROM itemTBL GROUP BY ItemID HAVING COUNT(Price) >= 4
You can then use this to later filter and get more information:
SELECT Item.*, Category.Name, Filter.NumPrices from itemTBL AS Item
INNER JOIN categoryTBL as Category ON Item.CategoryID = Category.CategoryID
INNER JOIN (SELECT ItemID, COUNT(Price) AS NumPrices FROM itemTBL GROUP BY ItemID HAVING COUNT(Price) >= 4) AS Filter on Item.ItemID = Filter.ItemID
This is the perfect thing for a group by:
SELECT ProductID, COUNT(*) AS PriceCount
FROM Product GROUP BY
Product,Price HAVING COUNT(Product) > 4

INNER JOIN: limit 0,1 on the second table

I have 2 tables, one called "products" and one "images".
The table "images" hold the images of each products, so I can have 5 image per product.
I want to make a select that retrive only 1 image for each product. I'm new to joins so i dont know how to solve this.
I'm trying with:
SELECT *
FROM products
INNER JOIN images ON products.id=images.prod_id
WHERE products.cat='shoes'
I need to add a Limit 0,1 on images table. How I can do it?
Thanks in advance.
Maybe a subselect is a better solution here.
Something like this:
SELECT
productId,
productName,
(SELECT imageData FROM Image i WHERE i.productId = productId LIMIT 1) AS imageData
FROM Products
It's best to avoid subqueries because they are slow in mysql.
If you want to get any image associated to product,
you can do it in fast but not very nice way:
SELECT *
FROM products
INNER JOIN images ON products.id=images.prod_id
WHERE products.cat='shoes'
GROUP BY products.id
If you want to get a first image( by any criteria ), apply groupwise max techniques
Take a look at DISTINCT
The key here is correlated subqueries.
select
*
from
products p,
(
select
*
from
images i
where
i.prod_id = p.id
limit 1
) as correlated
where
p.cat = 'shoes'
SELECT * FROM products
LEFT JOIN images ON products.id=images.prod_id
WHERE products.id='1' LIMIT 1
This will return the first image found for your product and all the product details.
If you want to retieve multiple products then I would suggest doing 2 queries.
SELECT product data
Loop through product data {
SELECT image data LIMIT 1
}
Doing complex single queries can quite often end up being more expensive than a couple/few smaller queries.

Categories