MySQL multiple table count query - sql

I have 3 tables
products
productid (int)
name (varchar)
price (float)
sales
salesid (int)
productid (int)
time (datetime)
links
linkid (int)
productid (int)
link (text)
Now I need a query that can display as
ProductID ProductName Sales Links
1 ABC 10 8
2 XYZ 15 12
I need all sales count and all links count for a particular product
How can I achieve this?
Thanks

SELECT p.productid, p.pname AS ProductName,
Count(DISTINCT s.salesid) as Sales, Count(DISTINCT l.linkid) as Links
FROM products p
LEFT JOIN sales s ON p.productid=s.productid
LEFT JOIN links l ON p.products=l.productid
GROUP BY p.productid

You need to write a cross-tab query.
This walk-through on the mysql site should help.
Or like in this tutorial

You can only use aggregate functions (like Count()) on the column specified in the GROUP BY clause, otherwise the aggregation is ambiguous. See the chapter "Ambiguous Groups" from the excellent book SQL Antipatterns for more reference.
In your case, the best option is to use two sub-queries:
SELECT p.productid as ProductID, p.pname AS ProductName,
(SELECT Count(*) FROM sales s WHERE p.productid=s.productid) as Sales,
(SELECT Count(*) FROM links l WHERE p.productid=l.productid) as Links,
FROM products p
GROUP BY p.productid
Not the most efficient query ever written, but it's perfectly ok as long as the tables doesn't contain a huge number of rows and/or you run it as a periodic report and not real-time on live data.
The best thing to do is to test it for yourself and see if the performance is acceptable.

Related

Lookup with duplicate values

This is kind of a complicated question. I have three tables:
A PRODUCTS table
ProductID
ProductName
Product A
Edwardian Desk
Product B
Edwardian Lamp
And a GROUPS table
ProductGroup
ProductID
Group A
Product A
Group A
Product B
Group B
Product C
And a SALES table
Product ID
Sales
Product A
1000
Product B
500
And I need to show the total of Sales per Product Group.
This part I understand; I wrote the query:
SELECT Groups.ProductGroup, SUM(Sales) AS TotalSales
FROM Groups
JOIN Sales
ON Groups.ProductID=Sales.ProductID
GROUP BY Groups.ProductGroup
This is the part that confuses me though: for each group, I need to pull in one of the names of the products in the group. However, it does not matter which name is pulled. So the final data could show:
Group A, Edwardian Desk, 1500
or
Group A, Edwardian Lamp, 1500
How can I pull the name of the product into my query?
I am working in Microsoft SQL Server
There's a number of ways to bring in one of your product's names, a couple of options are to either use an aggregation with a correlated subquery or to to use an apply.
Note, I've used aliases for your table names - doing so is good practice and makes queries more compact and easier to read. Also - presumably this is a contrived example and not your actual tables - but generally it's not a good practice to have column names identical to the table name, so if Sales on table Sales represents a quantity, then just call it Quantity!
select g.ProductGroup,
(select Min(ProductName) from Products p where p.ProductId=g.ProductId) FirstProductAlphabetically,
Sum(s.Sales) as TotalSales
from Groups g
join Sales s on s.ProductID=g.ProductID
group by g.ProductGroup
select g.ProductGroup,
p.ProductName as FirstProductById,
Sum(s.Sales) as TotalSales
from Groups g
join Sales s on s.ProductID=g.ProductID
cross apply (
select top (1) p.ProductName
from Products p
where p.ProductId=g.ProductId
order by ProductId
)p
group by g.ProductGroup
You can add products to the JOIN and use an aggregation function:
SELECT g.ProductGroup, SUM(s.Sales) AS TotalSales,
MIN(p.ProductName)
FROM Groups g JOIN
Sales s
ON g.ProductID = s.ProductID JOIN
Products p
ON p.ProductID = s.ProductId
GROUP BY g.ProductGroup;
Note: I often add two columns, MIN() and MAX() to get two sample names.
I should add. Your sample data has ProductIds that are not in the Products. That suggests a problem with either the question (more likely) or the data model. If you actually have references to non-existent products, then use a LEFT JOIN to Products rather than an inner join.

Error in products and sales table with same ProdID column name

Am getting the error Ambiguous column name 'ProdID' just after select because ProdID column is present in both SALES and PRODUCTS. I want to use the one in PRODUCTS.Description column is from SALES table. ProdID is the primary key in PRODUCTS table and foreign key in SALES table How can I do this?
select ProdID, Description
from PRODUCTS,
SALES
where PRODUCTS.ProdID = Sales.ProdID
and Price Between 10 and 18
Simply prefix the column with the table or table alias:
SELECT
P.ProdID
, S.Description
FROM
PRODUCTS AS P
INNER JOIN SALES AS S ON P.ProdID = S.ProdID
WHERE
Price Between 10 and 18
This also uses the ANSI standard way of performing a JOIN. Your syntax (using the WHERE clause) might at any point cease to be supported.
Your syntax would work the same way:
select PRODUCTS.ProdID, Description
from PRODUCTS,
SALES
where PRODUCTS.ProdID = Sales.ProdID
and Price Between 10 and 18
But again, you should seriously consider switching to proper JOINs. As you can see, all you do is add the JOIN keyword, and move the columns to the ON part instead of the WHERE clause.
select
P.ProdID,
S.Description
from PRODUCTS P, SALES S
where P.ProdID = S.ProdID
and s.Price Between 10 and 18

SQL a SELECT within a SELECT? Northwind (Microsoft)

First of all, I'm practicing with Northwind database (Microsoft creation).
The table design I'm working with is:
The question I'm trying to solve is:
Which Product is the most popular? (number of items)
Well, my query was:
SELECT DISTINCT
P.ProductName
FROM
Products P,
[Order Details] OD,
Orders O,
Customers C
WHERE
C.CustomerID = O.CustomerID
and O.OrderID = OD.OrderID
and OD.ProductID = P.ProductID
and P.UnitsInStock = (SELECT MAX(P.UnitsInStock) Items
FROM Products P)
Now, I had exactly one result as they asked:
ProductName
1 Rhönbräu Klosterbier
Yet, I doublt that my query was good. Do I really need a SELECT within a SELECT?
It feels like duplication for some reason.
Any help would be appreciated. Thanks.
To get the most popular product (bestselling product) use query
SELECT ProductName, MAX(SumQuantity)
FROM (
SELECT P.ProductName ProductName,
SUM(OD.Quantity) SumQuantity
FROM [Order Details] OD
LEFT JOIN Product P ON
P.ProductId = OD.ProductID
GROUP BY OD.ProductID
) Res;
Does the most units in stock necessarily equate to the most popular product? I don't think that is always a true statement (It could even be the opposite in fact.).
To me the question is asking, which is the most popular product sold. If you think about it that way, you'd be looking at the amount sold for each product and selecting the product with the most sold.
Does that make sense?
With regards to your specific query, the query only utilizes the Products table. You make joins, but they are not used at all in the query and should get overlooked by the query optimizer.
I would personally rewrite your query as the following:
SELECT
P.ProductName
FROM
Products P
INNER JOIN
(SELECT
MAX(P.UnitsInStock) AS Items
FROM Products P) maxProd
ON P.UnitsInStock= maxProd.Items
About your question, it is perfectly acceptable to utilize a subquery (the select in the where clause). It is even necessary at times. Most of the time I would use an Inner Join like I did above, but if the dataset is small enough, it shouldn't make much difference with query time.
In this scenario, you should rethink the question that is being asked and think about what being the most popular item means.
Rethinking the problem:
Let's look at the datasets that you've shown above. Which could be used to tell you how many products have been sold? A customer would have to order a product, right? Looking at the two tables that are potentially applicable, one contains details about number of items sold, quantity, or you could think of popularity in terms of the number of times appearing in orders. Start with that dataset and use a similar methodology to what you've done, but perhaps you'll have to use a sum and group by. Why? Perhaps more than one customer bought the item.
The problem with the dataset is it doesn't tell you the name of the product. It only gives you the ID. There is a table though that has this information. Namely, the Products table. You'll notice that both tables have the Product ID variable, and you are able to join on this.
You can find the most popular product by counting the number of orders placed on each product .And the one with most number of order will be the most popular product.
Below script will give you the most popular product based on the the number of orders placed .
;WITH cte_1
AS(
SELECT p.ProductID,ProductName, count(OrderID) CNT
FROM Products p
JOIN [Order Details] od ON p.ProductID=od.ProductID
GROUP BY p.ProductID,ProductName)
SELECT top 1 ProductName
FROM cte_1
ORDER BY CNT desc
if you are using SQL server 2012 or any higher version, use 'with ties' for fetching multiple products having same order count.
;WITH cte_1
AS(
SELECT p.ProductID,ProductName, count(OrderID) CNT
FROM Products p
JOIN [Order Details] od ON p.ProductID=od.ProductID
GROUP BY p.ProductID,ProductName)
SELECT top 1 with ties ProductName
FROM cte_1
ORDER BY CNT desc
In your sample code,you tried to pull the product with maximum stock held. since you joined with other tables (like order details etc) you are getting multiple results for the same product. if you wanted to get a product with maximum stock,you can use any of the following script.
SELECT ProductName
FROM Products P
WHERE P.UnitsInStock = (SELECT MAX(P.UnitsInStock) Items
FROM Products P)
OR
SELECT top 1 ProductName
FROM Products P
ORDER BY P.UnitsInStock desc
OR
SELECT top 1 with ties ProductName --use with ties in order to pull top products having same UnitsInStock
FROM Products P
ORDER BY P.UnitsInStock desc

How to Make a Query to Return Non-Dup values From Two Tables

Suppose the following:
Table Parts
--------------------------------
ID Category Name Price
--------------------------------
1 A Processor 100
2 A MotherBoard 80
3 B Memory Card 40
4 B HD 70
5 C Cooler 10
Table Product_Views
-----------------------------------
Customer Date Part_ID
-----------------------------------
Bill mar-24-15 17:45 1
Wallace mar-25-15 08:17 4
Heather mar-25-15 08:43 1
Chuck mar-25-15 09:01 5
Cindy mar-25-15 11:23 1
How can I build a SQL query in order to retrieve most viewed parts showing: Category, price and number of views, grouped by Category, WITHOUT a sum on Price column? Must I do a subquery or there's a trick to do that in a simple [INNER/LEFT/RIGHT] JOIN?
select p.ID, p.Name, p.price, Count(v.*) "Number of Views"
from parts p
join product_views v
on p.id = v.part_id
group by p.ID, p.Name, p.price
order by Count(v.*) desc
Something along those lines should work.
EDIT for category:
Sorry I've been out for a while. What do you want to do with the category? If you just need it included for analysis you can just add it to the select and group by statements, like the following:
select p.ID, p.Category, p.Name, p.price, Count(v.*) "Number of Views"
from parts p
join product_views v
on p.id = v.part_id
group by p.ID, p.Category, p.Name, p.price
order by Count(v.*) desc
If however you want to see how many views there are per category, you will either need to average your price or leave the price off. If you think about it, in a category you have multiple items with different prices each. So you need some way to unify those prices in order to have a single price point per category. Generally (not always), the average price is the most indicative price of how a category is doing. A query to look at the information at the category level would look something like the following:
select p.Category, AVG(p.price) "Average Price", Count(v.*) "Number of Views"
from parts p
join product_views v
on p.id = v.part_id
group by p.Category
order by Count(v.*) desc
In order to leave off the price, just remove the AVG(p.price) "Average Price" from the query.
You can compare this last query to the previous one and see that the differences are all in the select and group by statements. The select is going to have all of the different things that you want to see and the group by statement is going to choose at what level you want to see those things. So if you want to see how your categories are doing on a whole, then the most detail that you want to group by will be just the category column. If you want to see how well each item is doing, then you will want to group by the ID or name of each item.

SQL query for showing the products which sell better, based on how many times an index is found in the table?

I have customer table which have products and quantity , I need to retrieve those products which sell better in the company.
How would I accomplish this with an SQL query?
Out of the common-assumption of a product/order/sales table schema, the following query is constructed. So please either show us your tables or change the query according to your tables.
This will give you the best product:
SELECT s.ProductID, ProductName, Max(s.Quantity) as MaxSales
FROM Products p, SalesOrder s
WHERE p.ProductID = s.ProductID
GROUP BY s.ProductID;
This will give you 10 best products:
SELECT TOP 10 s.ProductID, ProductName, s.Quantity
FROM Products p, SalesOrder s
WHERE p.ProductID = s.ProductID
ORDER BY s.Quantity DESC;
I think a simple order by clause should do
select products, quantity
from tableName
order by quantity desc
If you need only top 5 for example, add "Top 5" between select and products word in above query
Hope that helps