SQL: Order by count return only the first row - sql

I have two tables products and product_views.
I want to write a query that returns the products with the largest number of views.
products table has id and name columns. product_views has columns id, customer_id, product_id. The counting is based on the product_id column.
Here is my query:
SELECT *
FROM products
LEFT JOIN product_views ON products.id = product_views.product_id
ORDER BY COUNT(product_views.product_id) DESC;
The problem is it returns only the first product. I think the issue is that initially the product_views table is all empty (all values are null).
How to solve this issue?

Based on your criteria, the following should work -
SELECT
p.id,
p.name,
count(v.product_id) as views
FROM products p
LEFT JOIN product_views v
ON p.id = v.product_id
GROUP BY 1,2
ORDER BY views DESC;
The query ignores customer_id, and counts product_ids based on the id/name groupings.

Calculates count in separate script:
SELECT products.id, products.name, pv.count FROM products
JOIN (SELECT product_id, COUNT(*) as count FROM product_views GROUP BY product_id)
pv ON (products.id = product_id )
ORDER BY pv.count DESC;
Example: SQL Fiddle

Related

How to sort customer names by items purchased in SQL

Sorry new to this but,
I need to sort customer names by total quantity of items purchased by them, in desc order.
the purchased amount in the table is known as Inv_number
I would need the customer name and than the sum. This is what it should be
Thanks
I don't know what your tables are named or what fields they have on them, so I'll give a generic example:
SELECT c.CUST_NAME AS "cust_name",
SUM(oi.QTY_PURCHASED) AS "sum"
FROM CUSTOMERS c
INNER JOIN ORDERS o
ON o.ID_CUSTOMERS = c.ID_CUSTOMERS
INNER JOIN ORDER_ITEMS oi
ON oi.ID_ORDERS = o.ID_ORDERS
GROUP BY c.CUST_NAME
ORDER BY SUM(oi.QTY_PURCHASED) DESC,
c.CUST_NAME ASC
db<>fiddle here
Should work this way - you have to join the tables for customerinfo (customer in this script) and the items purchased (order_items). For simplicity I only made an example with two tables. if the customer_id is present in a kind of "order" table, you have to join order_items -> order -> customer
SELECT
x.customer_name,
y.customer_amount
FROM customer x
INNER JOIN (
SELECT
customer_id,
SUM(order_amount) AS customer_amount
FROM order_items
GROUP BY customer_id
) y ON x.id = y.customer_id
ORDER BY y.customer_amount DESC;

SQL - Sum Up Results Of A Multiplication By Group

I have the following tables:
Orders (OID, Count, ProductID, TableNr)
Table (TableNr, Name, Number)
Products (ProductID, Prize)
Now I want to calculate how much was earned per table. I think to do this I have to Group By Orders.TableNr. But how can I multiply the Products.Prize with the Orders.Count and after that sum up this results within the group?
You are describing a join and aggregation:
select o.tableNr, sum(o.count * p.prize) totalEarned
from orders o
inner join products p on p.productId = o.productId
group by o.tableNr
If you want to display table information as well (say, the table name), then you can add another join:
select t.tableNr, t.name, sum(o.count * p.prize) totalEarned
from table t
inner join orders o on o.tableNr = t.tableNr
inner join products p on p.productId = o.productId
group by t.tableNr, t.name
Note that table is a SQL keyword, hence not a good choice for a table name.

SQL: How to group by with two tables?

I have the tables products and history and I need to group by name:
products = (id_product, name)
history = (id_history, id_product, amount)
I tried this SQL query but it isn't grouped by name:
SELECT
products.name,
sum(history.amount)
FROM history
INNER JOIN products ON history.id_product = products.id_product
GROUP BY
products.name,
history.amount,
history.id_history;
This is the result:
You should only be grouping by the attributes you need to be aggregated. In this case, you need only products.name.
SELECT
products.name,
sum(history.amount) AS [Amount]
FROM history
INNER JOIN products ON history.id_product = products.id_product
GROUP BY
products.name;
If you need to include products without history (assuming sum should be 0 instead of null in this case), then you can use an OUTER JOIN instead of INNER JOIN to include all products:
SELECT
products.name,
COALESCE(sum(history.amount), 0) AS [Amount]
FROM history
RIGHT OUTER JOIN products ON history.id_product = products.id_product
GROUP BY
products.name;
This is no answer, but too long for a comment.
For readability's sake the product table should be first. After all it is products that we select from, plus a history sum that we can access via [left] join history ... followed by an aggregation, or [left] join (<history aggregation query>), or a subselect in the select clause.
Another step to enhance readability is the use of alias names.
Join the table, then aggregate
select p.name, coalesce(sum(h.amount), 0) as total
from products p
left join history h on h.id_product = p.id_product
group by p.name
order by p.name;
Aggregate, then join
select p.name, coalesce(h.sum_amount, 0) as total
from products p
left join
(
select sum(h.amount) as sum_amount
from history
group by id_product
) h on h.id_product = p.id_product
order by p.name;
Get the sum in the select clause
select
name,
(select sum(amount) from history h where h.id_product = p.id_product) as total
from products p
order by p.name;
And as you were confused on how to use GROUP BY, here is an explanation: GROUP BY ___ means you want one result row per ___. In your original query you had GROUP BY products.name, history.amount, history.id_history saying you wanted one result row per name, amount, and id, while you actually wanted one row per name only, i.e. GROUP BY products.name.

SQL Compact Edition LEFT OUTER JOIN Average

I have a table with products and a table with ratings. I have the following query;
SELECT products.name, ratings.rating
FROM products
LEFT OUTER JOIN ratings
ON products.id = ratings.product_id;
Returning me a nice list of rows with the name of the product and every rating separately.
I am trying to achieve that it returns one row showing me the name of the product with its average rating. Can't seem to find out how though.
Thanks in advance.
You want to look into the GROUP BY statement. Example:
SELECT products.name AS Product_Name,
AVG(ratings.rating) AS Average_Rating
FROM products
LEFT OUTER JOIN ratings
ON products.id = ratings.product_id
GROUP BY products.name
ORDER BY products.name;
Whilst using the GROUP BY statement, you may wish to filter your resultset on the outcome of one or more of your aggregate functions. You use the HAVING statement to do so:
SELECT products.name AS Product_Name,
AVG(ratings.rating) AS Average_Rating
FROM products
LEFT OUTER JOIN ratings
ON products.id = ratings.product_id
GROUP BY products.name
HAVING AVG(ratings.rating) >= 3
ORDER BY products.name;

Select top and order from two tables

I am doing an e-commerce marketplace. There are many sellers selling in this marketplace. For each seller, I would like to display a Best Sellers list.
Database is in SQL Server. There are 2 main tables in this case:
Table 1: Stores each order's ordered products. Fields include SellerID, OrderID, ProductID, and Quantity.
Table 2: The products master table. Fields include ProductID, ...
How can I do a query to get the top 10 products with the most orders? My SQL below doesn't seem to work...
SELECT TOP (10) SUM(d.Quantity) AS total, d.ProductID, p.Title
From OrderDetails d, Products p
WHERE d.SellerID = 'xxx' AND
d.ProductID = p.ProductID
GROUP by d.ProductID
ORDER BY total DESC
Any help is much appreciated. Thank you!
select *, d.s
from products p
inner join
(
select top 10 productid, sum(quantity) as s
From OrderDetails
group by productid
order by sum(quantity) desc
)
d on d.productid = p.productid
See this SQLFiddle example
This is just a guess. If you want the "most orders" then I would rather count the orders instead of summing the quantity.
SELECT TOP 10
COUNT(d.OrderID) AS total, d.ProductID, p.Title
FROM OrderDetails d
INNER JOIN Products p ON d.ProductID = p.ProductID
WHERE d.SellerID = 'xxx'
GROUP by d.ProductID, p.Title
ORDER BY COUNT(d.OrderID) DESC
What else I fixed:
GROUP BY was missing a column. You have to name every column you have in your SELECT clause but is not in an aggregate function.
In the ORDER BY clause you have to name it exactly like you did in SELECT clause. Aliases don't work well in SQL Server.
Used the INNER JOIN syntax, which is less error prone to forgetting to specify the join in the WHERE clause.
This is not because of what type of database you using but aggregate function. There are lots of q & a regarding of this problem in stackoverflow. Please search for it.