How to count from a single table whilst performing multiple joins - mysql

I was asked the following question:
Find the 3 vendors that supply our most famous products by number of units sold, not number of units ordered. Rank them first to third.
The database used is the online classicmodels db: http://mysqltutorial.org//tryit/
This is what I have done, I cannot seem to count the payments only and group by vendors. The count I get back is a product of all the joins.
SELECT p.productvendor FROM products AS p
INNER JOIN orderdetails AS od ON p.productcode = od.productcode
INNER JOIN orders AS o ON o.ordernumber = od.ordernumber
INNER JOIN customers AS c ON c.customernumber = o.customernumber
INNER JOIN payments AS py ON py.customernumber = c.customernumber
GROUP BY p.productvendor
ORDER BY COUNT(p.productvendor) DESC
LIMIT 3

Try to break the problem into smaller queries and then try to optimize the joins.
select count(p.productvendor) as product_count, p.productvendor from (JOINS) group by p.productvendor
-- this should give count by vendor. you can use sum(orderdetails.qty) also in case you
So the problem is reduced to be in the JOINS
JOINS ( has to be a collection of individual product sales)

Related

MySQL: how many different customers ordered

i have a question with the data base Northwind
i need to Write a query that will retrieve for each Product the product name and how many different customers ordered it when the number of customers who ordered the same product must be at least 2, ie at least two different customers ordered the product
i did something like that but idk how to continue
thx
SELECT p.ProductID,p.ProductName ,count(CustomerId)
FROM Products p
join `order details` oon p.ProductID=o.ProductID AND Quantity>=2
join Orders kk where kk.OrderID=o.OrderID
group by p.ProductID
order by p.ProductID
The question says that the number of customers must be at least 2, not the quantity that they ordered. You can do this in a HAVING clause that compares the aggregate count.
You need to use COUNT(DISTINCT CustomerId) so you don't count the same customer multiple times for each order.
SELECT p.ProductID,p.ProductName ,count(DISTINCT kk.CustomerId) AS numCustomers
FROM Products p
join `order details` on p.ProductID=o.ProductID
join Orders kk on kk.OrderID=o.OrderID
group by p.ProductID
order by p.ProductID
HAVING numCustomers >= 2

Query returns false information on column

If you run this:
SELECT o.orderid,suppliername,p.productname
FROM Suppliers s
JOIN Orders o
ON o.shipperid = s.supplierid
JOIN OrderDetails od
ON od.orderid = o.orderid
JOIN Products p
ON p.productid = od.productid
On https://www.w3schools.com/sql/trymysql.asp?filename=trysql_func_mysql_count
You get resuls where for each order-id, there is a set of rows with productnames and suppliernames.
Now, the funny thing is that for each Order as a whole (say a set of two rows for order 10300)
there is always the SAME suppliername.
But this isnt true. When you look up the table "products" you will find that for example for the products with ID 66 and 68, which are the products contained in order 10300, there are two different supplier IDs registered. 2 and 8.
And these resolve to two different suppliernames on the supplieres table.
Why is that? This is a fairly simple query in my opinion, I didnt expect to run into any issues with it. But here, the data presented to me in the tables and the data returned by the query clearly diverge.
Am I missing something or is their site/DB just broken?
The error is caused by the way you are joining to the Suppliers table. Instead of joining the Suppliers table to the Orders table, it seems like you want to join the Products to the Suppliers tables to get the suppliers for those products. Such a query would look like:
SELECT o.orderid, s.suppliername, p.productname
FROM Orders o
JOIN OrderDetails od ON od.orderid = o.orderid
JOIN Products p ON p.productid = od.productid
JOIN Suppliers s ON s.supplierid = p.supplierid

Related products approach suggestion, MySQL InnoDB/PHP

I want to expand UI on my CodeIgniter shop with suggestions on what other people bought with the current product (either when viewing product or when product is put in the cart, irrelevant now for the question).
I have came up with this query (orders table contains order details, while order items contains products that are in specific order via foreign key, prd alias is for products table where all important info about prduct is stored).
Query looks like this
SELECT
pr.product_id,
COUNT(*) AS num,
prd.*
FROM
orders AS o
INNER JOIN order_items AS po ON o.id = po.order_id
INNER JOIN order_items AS pr ON o.id = pr.order_id
INNER JOIN products AS prd ON pr.product_id = prd.id
WHERE
po.product_id = '14211'
AND pr.product_id <> '14211'
GROUP BY
pr.product_id
ORDER BY
num DESC
LIMIT 3
It works nice and dandy, query time is 0.030ish seconds and it returns the products that bought together with the one I am currently viewing.
As for the questions and considerations, Percona query analyzer complains about this two things, Non-deterministic GROUP BY and GROUP BY or ORDER BY on different tables, which both I need so that I can get items on top that are actually relevant for the related query, but absolutely have no idea how to fix it, or even should I be really bothered with this notice from query analyzer.
Second question is regarding performace, since for this query, it using temporary and filesort, I was thinking of creating a view out of this query, and use it instead of actually executing the query each time some product is opened.
Mind you that I am not asking for CI model/view/controller tips, just tips on how to optimize this query, and/or suggestions regarding performance and going for views approach...
Any help is much than appreciated.
SELECT p.num, prd.*
FROM
(
SELECT a.product_id, COUNT(*) AS num
FROM orders AS o
INNER JOIN order_items AS b ON o.id = b.order_id
INNER JOIN order_items AS a ON o.id = a.order_id
WHERE b.product_id = '14211'
AND a.product_id <> '14211'
GROUP BY a.product_id
ORDER BY num DESC
LIMIT 3
) AS p
JOIN products AS prd ON p.product_id = prd.id
ORDER BY p.num DESC
This should
Run faster (especially as your data grows),
Avoid the group by complaint,
not over-inflate the count,
etc
Ignore the complaint about GROUP BY and ORDER BY coming from different tables -- that is a performance issue; you need it.
As for translating that back to CodeIgniter, good luck.

Getting info through 3 tables

I'm following the SQL tutorial from w3schools.
I want to get the value of all orders delivered by a shipper. I don't have any idea about how I can get these details as the info are in different tables and the INNER JOIN didn't worked for me.
Database: http://www.w3schools.com/sql/trysql.asp?filename=trysql_select_groupby
By now, I managed to get the number of orders by each shipper.
SELECT Shippers.ShipperName,COUNT(Orders.OrderID) AS NumberOfOrders FROM Orders
LEFT JOIN Shippers
ON Orders.ShipperID=Shippers.ShipperID
GROUP BY ShipperName;
How could I get the value of those?
To bring the Price of a Product into your query you will need to join in tables OrderDetails to the Order table on the Orders.Id and then join in the Products table to the OrderDetail table on ProductID
SELECT Shippers.ShipperName,
COUNT(Orders.OrderID) AS NumberOfOrders,
Sum(Products.price * OrderDetails.Quantity) AS SumOfPrice
FROM Orders
LEFT JOIN Shippers ON Orders.ShipperID = Shippers.ShipperID
LEFT JOIN OrderDetails ON ORders.OrderID = OrderDetails.OrderID
LEFT JOIN Products ON OrderDetails.ProductID = Products.ProductID
GROUP BY ShipperName;
I just stuck with LEFT JOIN here as your example used, but an INNER JOIN would work just as well and be more efficient.
The FROM clause of the SQL statement is one of the first parts of the SQL to run against your database. It establishes which tables we are grabbing information from and the relationship between those tables (using the ON keyword). So here we bring in 4 tables, and use the ON keyword to show the relationship between all of them using their respective IDs. Then we can add their fields to the SELECT portion of the SQL statement and aggregate where needed.
If you want the "sum" of the product prices, that would be very similar to what you already have. Note how you currently use the COUNT() function to get the count, you can use the SUM() function to get the total of any numeric column.
Something like this:
SELECT
Shippers.ShipperName,
COUNT(Orders.OrderID) AS NumberOfOrders,
SUM(Products.Price) AS PriceOfOrders
FROM
Orders
INNER JOIN Shippers ON Orders.ShipperID = Shippers.ShipperID
INNER JOIN OrderDetails ON Orders.OrderID = OrderDetails.OrderID
INNER JOIN Products ON OrderDetails.ProductID = Products.ProductID
GROUP BY
ShipperName
Or perhaps the price also needs to be multiplied by the quantity in this calculation? Something like this:
SELECT
Shippers.ShipperName,
COUNT(Orders.OrderID) AS NumberOfOrders,
SUM(Products.Price * OrderDetails.Quantity) AS PriceOfOrders
FROM
Orders
INNER JOIN Shippers ON Orders.ShipperID = Shippers.ShipperID
INNER JOIN OrderDetails ON Orders.OrderID = OrderDetails.OrderID
INNER JOIN Products ON OrderDetails.ProductID = Products.ProductID
GROUP BY
ShipperName
It's up to your understanding of the table structure and the data, really. But the concept is the same, grouping by a value and applying a calculation to the grouped values (count or sum).

inner-join mysql joining 3 tables

i am having problems using an inner join for 3 tables..
i need to display cust_id, the customer forename and surname, the product name<-(from products table) and date of sale<--(from sales table), also i need to display in order of the most recent dates first.
this is what i have got so far
enter SELECT
customers.cust_id,
customers.forename,
customers.surname,
products.prod_name,
sales.Date_of_sale
FROM
customers
INNER JOIN
sales
ON
customers.cust_id = sales.cust_id; here
id really appreciate it if you could help me here, thank you..
Just add one more JOIN to the products table and include an ORDER BY clause:
SELECT
c.cust_id,
c.forename,
c.surname,
p.prod_name,
s.Date_of_sale
FROM customers c
INNER JOIN sales s ON c.cust_id = s.cust_id
INNER JOIN products p ON s.product_id = p.product_id
ORDER BY s.Date_of_sale DESC
A Visual Explanation of SQL Joins
I think the problem is in your FROM parameter.
You specified only customer.
SELECT customers.cust_id, customers.forename, customers.surname, products.prod_name, sales.Date_of_sale
FROM
customers , products , sales
INNER JOIN
sales
ON
customers.cust_id = sales.cust_id;