Returning average rating from a database (SQL) - php

I'm trying to create a rating system, where the user can rate pictures/videos/audio etc. I have two tables at the moment
Table: products
Cols: product_id[PK] | name | category | type | link
This is the products table and contains information about the products. If you're confused by products, think of the "product" as the image/video/audio, I named it like this simply for allowing me to understand it easier. The second table is the ratings
Table: product_ratings
Cols: rating_id[PK] | rating | product_id | timestamp
This table stores information about the rating the user has given.
I want a page where it will display the highest rating (on average) for all "products". So far, I've looked through SA, and found the follow piece of code:
SELECT
p.product_id, p.name,
AVG(pr.rating) AS rating_average
FROM products p
INNER JOIN product_ratings pr
ON pr.product_id = p.product_id
WHERE p.product_id = 1
This just returns the average rating for a specific product_id, How would I go about getting ALL the product_ids and their average rating, and how would I find the highest one via PHP?
I've tried:
WHERE p.product_id < 1 AND p.product_id < 30
But this just returns product_id of 2, with it's name and average_rating, which I don't understand.
Guidance/links to material are welcome

SELECT
p.product_id,
p.name,
AVG(pr.rating) AS rating_average
FROM products p
INNER JOIN product_ratings pr
ON pr.product_id = p.product_id
GROUP BY p.product_id
ORDER BY rating_average DESC
LIMIT 1

Just try:
SELECT
p.product_id, p.name,
AVG(pr.rating) AS rating_average
FROM products p
INNER JOIN product_ratings pr
ON pr.product_id = p.product_id
also this is meaningless expression:
WHERE p.product_id < 1 AND p.product_id < 30
because it is completely equivalent to
WHERE p.product_id < 1
and i doubt that you have ids below zero

Your query is close. Just remove the WHERE clause that filters everything.
SELECT p.product_id, p.name,
AVG(pr.rating) AS rating_average
FROM products p
INNER JOIN product_ratings pr
ON pr.product_id = p.product_id
ORDER BY rating_average DESC
This will return you the averages for each product, sorted with the highest average rating at the top of the resultset.

Related

MySQL need sub select or temporary table

I have 2 tables.
First table - products
products_id | quantity
1001,1
1002,2
1003,5
1004,4
Second table - products_catalog
products_catalog_id | products_id | partner_channel |active_status
1,1001,amazon,0
2,1001,ebay,0
3,1001,zalando,1
4,1002,amazon,1
5,1002,ebay,0
6,1003,amazon,1
7,1003,ebay,1
8,1003,zalando,1
9,1004,amazon,0
10,1004,ebay,0
11,1004,zalando,0
I want to have result of the products id with the condition if this product is not active in any partner channel (active_status = 0)
I was using WHERE filter like this:
SELECT p.products_id, pc.partner_channel, pc.active_status
FROM products p
LEFT JOIN products_catalog pc ON pc.products_id=p.products_id
WHERE pc.active_status='0'
GROUP BY p.products_id ORDER BY p.products_id;
WHERE active_status = 0, but the result was like this:
products_id | partner_channel | active_status
1001,amazon,0
1002,ebay,0
1004,amazon,0
I want to have result table products like this:
products_id | partner_channel | active_status
1004,amazon,0
Because in all partner_channel only this product id (1004) that have active_status = 0.
I think i missed something in the WHERE filter, but didn't have any clue about that. Maybe i should use sub query in when LEFT JOIN to products_catalog?
Any help will be appreciated.
Thanks.
use Having function.
SELECT p.products_id, ANY_VALUE(pc.partner_channel), ANY_VALUE(pc.active_status)
FROM products p
LEFT JOIN products_catalog pc ON pc.products_id=p.products_id
GROUP BY p.products_id
having sum(pc.active_status)=0
ORDER BY p.products_id;
You have to place a condition in the HAVING clause like this:
SELECT products_id
FROM products_catalog
GROUP BY products_id
HAVING SUM(active_status <> 0) = 0;
This query returns all products_id values having active_status = 0 for all partner_channel they are related to.
You can then use the above query as a derived table to join back to the original tables in order to get the rest of the fields:
SELECT p.*, pc.*
FROM products p
JOIN products_catalog pc ON pc.products_id=p.products_id
JOIN (
SELECT products_id
FROM products_catalog
GROUP BY products_id
HAVING SUM(active_status <> 0) = 0
) AS g ON g.products_id = p.products_id
ORDER BY p.products_id
Demo here
Try this Code
SELECT p.products_id, pc.partner_channel, pc.active_status
FROM products p
LEFT JOIN products_catalog pc ON pc.products_id=p.products_id
WHERE pc.active_status='0'
GROUP BY p.products_id ORDER BY p.products_id DESC;

Mysql Join with WHERE min(value)

I have this problem
I have 2 Tables
1. product_detail
-id
-name
-thumb
2. product_sale
-id
-pid
-fid
-price
-package
.
SELECT *
FROM product_sale
WHERE MIN(product_sale.price)
JOIN product_detail
ON product_detail.id = product_sale.pid
ORIGINAL SELECT SORRY POSTED WRONG
SELECT * FROM product_detail INNER JOIN product_sale ON product_detail.id = pid
I Have 1 Product in product_detail Example Product1
I Have Many rows in product_sale for Product1 but different product_sale.fid and product_sale.price
What i need to do ist make a select that display Product1 With Lovest Price in product_sale
1 Product1 1.50 1pz
2 Product2 2.50 3pz
3 Product3 3.00 1pz
Now i Get
1 Product1 1.50 1pz
2 Product1 1.65 1pz
3 Product1 1.70 1pz
4 Product3 3.00 1pz
Please helpme what select i need to do ??Thank You All
Barring subqueries, you can't JOIN after a WHERE, and I am pretty sure you can't use MIN in a WHERE either. However, you can WHERE a subquery that contains a MIN.
SELECT *
FROM product_sale AS ps INNER JOIN product_detail AS pd ON ps.pid = pd.id
WHERE (ps.pid, ps.price) IN (
SELECT pid, MIN(price)
FROM product_sale
GROUP BY pid
);
Note that if the product is sold at the lowest price multiple times, you will get multiple rows for it. I am not clear on what the #pz values are supposed to be, but perhaps the * in my answer should be pd.id, pd.name, COUNT(1) AS pz and GROUP BY pd.id, pd.name placed before the ;
Edit: The below should get the "last sale" asked about in the comments below this answer.
SELECT *
FROM product_sale AS ps3
INNER JOIN product_detail AS pd ON ps3.pid = pd.id
WHERE ps3.fid IN (
SELECT MAX(ps2.fid) AS lastFidsForPidsAtLowestPrices
FROM product_sale AS ps2
WHERE (ps2.pid, ps2.price) IN (
SELECT ps1.pid, ps1.MIN(price) AS lowestPriceForPid
FROM product_sale AS ps1
GROUP BY ps1.pid
)
GROUP BY ps2.pid
)
;
Seems to be a straight forward join with a group by and a min..
SELECT PD.name, min(price) as LowestSoldPrice, PD.Thumb, PS.Package
FROM product_Detail PD
LEFT JOIN product_Sale PS
on PD.ID = PS.PID
GROUP BY PD.name, PD.Thumb, PS.Package
I don't understand your query at all. I was surprised it produced anything but an error. This is what I would do.
select pd.id productid,
min(pd.name) name, -- min just so I do not have a complex group by
min(ps.price) minprice
from product_detail pd
join product_sale ps
on pd.id=ps.pid
group by pd.id
This will give you one row per product ID with the name of the product and the min price.
SELECT ps.*, pd.*
FROM product_sale ps
LEFT JOIN product_sale t
ON ps.pid = t.pid AND ps.price>t.price
LEFT JOIN product_detail pd
ON pd.id = product_sale.pid
WHERE t.pid IS NULL
But as many people here I wonder if you really need GROUP BY. What is accepted behavior if you have 2 or more sales with the same minimum price? Should all records be returned? or just one? which one then?

Mysql function count() counts rows individually

I have the following query, where i want to get the total number of rows but this seems to count each individually here is the query and the result
SELECT
COUNT(pc.product_id)
FROM
products as p
INNER JOIN product_categories as pc
ON p.product_id = pc.product_id AND pc.subcategory_id IN (77)
GROUP BY pc.product_id
HAVING COUNT(pc.subcategory_id) = 1
Result is :
COUNT(pc.product_id)
1
1
1
...but it should be
COUNT(pc.product_id)
3
UPDATE
the above query should count the number of products that are get by this query
SELECT
*
FROM
products as p
INNER JOIN product_categories as pc
ON p.product_id = pc.product_id AND pc.subcategory_id IN ($sb_2)
GROUP BY pc.product_id
HAVING COUNT(DISTINCT pc.subcategory_id) = $sb_count
$sb_2 = 77,76;
$sb_count = how many values are in $sb_2;
77 and 76 are different subcategories ids but are common for some products
If you know another way to count this or to make another query...
SELECT
COUNT(pc.product_id)
FROM
products as p
INNER JOIN product_categories as pc
ON p.product_id = pc.product_id AND pc.subcategory_id IN (77)
HAVING COUNT(pc.subcategory_id) = 1
Removing the group by should do the trick.
I manage to count rows by the following query.
"SELECT COUNT(*) as count FROM (SELECT
*
FROM
product_categories WHERE subcategory_id IN (77,76)
GROUP BY product_id
HAVING COUNT(DISTINCT subcategory_id) = 2) as subc";
}

MySQL: Get products having all attributes listed

I'm having some problems to get this query works as I expect.
I have three tables: products, product_attributes and attributes.
The relation is obvious (A product can have multiple attributes)
products
---------
id
product_attributes
------------------
product_id
attribute_id
attributes
----------
id
name
What I want to achieve is to get those products that has a given list of attributes, BUT omit those products that only has a partial list of the desired attributes.
For example, having these products and attributes:
Shoe 1 [blue,boy]
Shoe 2 [blue,girl]
Shoe 3 [red,boy]
Shoe 4 [red,girl]
A query asking for those products with [blue,boy] would retrieve only Shoe 1.
A query asking for those products with [blue] would not return anything.
Since now I was working with this query:
SELECT p.*, pa.attribute_id
FROM products AS p
LEFT JOIN product_attributes AS pa ON(pa.product_id=p.id)
WHERE
pa.attribute_id IN(' . implode(',', $attr_ids) . ')
GROUP BY p.id
HAVING count(pa.attribute_id)=' . count($attr_ids)
This fails when just an attribute is given because it will return any product having that attribute.
-- PHP (or any other languaje) parts are hardcoded here!!!!
SELECT p.*, hma.howmuchattr
-- howmuchattr is needed by HAVING clause,
-- you can omit elsewhere (by surrounding SELECT or by programming languaje)
FROM products AS p
LEFT JOIN product_attributes AS pa ON pa.product_id = p.id
LEFT JOIN (
SELECT product_id, count(*) as howmuchattr
FROM product_attributes
GROUP BY product_id
) as hma on p.id = hma.product_id
WHERE
pa.attribute_id IN
(1,3) -- this cames from PHP (or any other languaje). Can be (1) for the other case
GROUP BY p.id
HAVING count(*) = howmuchattr;
see sqlfiddle here
see also this answer
Aside from any other issues, this query...
SELECT p.*
, pa.attribute_id
FROM products p
LEFT
-- OUTER (this keyword is optional in MySQL)
JOIN product_attributes pa
ON pa.product_id = p.id
WHERE pa.attribute_id IN('$attr_ids')
GROUP
BY p.id
HAVING COUNT(*) = $cnt;
... is logically identical to...
SELECT p.*
, pa.attribute_id
FROM products p
-- INNER (this keyword is also optional in MySQL)
JOIN product_attributes pa
ON pa.product_id = p.id
WHERE pa.attribute_id IN('$attr_ids')
GROUP
BY p.id
HAVING COUNT(pa.attribute_id) = $cnt;
In order to maintain the utility of the OUTER JOIN consider rewriting as follows...
SELECT p.*
, pa.attribute_id
FROM products p
LEFT
JOIN product_attributes pa
ON pa.product_id = p.id
AND pa.attribute_id IN('$attr_ids')
GROUP
BY p.id
HAVING COUNT(pa.attribute_id) = $cnt;

Fetching product categories in one row with product info

I have 3 tables
products categories products_categories
------------ ------------- --------------------
product_id category_id product_id
product_title category_title category_id
Each product can belong to multiple categories as the db schema shows.
I join the three tables to get a listing of the three last inserted products.
SELECT p.product_id,
p.product_title,
c.category_id,
c.category_title
FROM products p
INNER JOIN products_categories pc ON p.product_id = pc.product_id
INNER JOIN categories c ON pc.category_id = c.category_id GROUP BY p.product_id LIMIT 3
With the above query I get the products but with the first category that the product belongs to.
My question is, is it possible by modifying the query to get all the categories that each product belongs to, in one row along with the product info?
Or the only way is to execute another query for each product while fetching the list to get its categories?
You could try:
SELECT p.product_id, p.product_title,
GROUP_CONCAT(c.category_title)
FROM products p
INNER JOIN products_categories pc ON p.product_id = pc.product_id
INNER JOIN categories c ON pc.category_id = c.category_id
GROUP BY p.product_id
See GROUP_CONCAT syntax here
Dont use "Group By". Then in your PHP Code group manually to product_id and collect all categories.

Categories