Is there a way to answer this question without using joins?
Write a query that finds, for each customer X, another customer Y who has ordered at least one product in common with X. Find all such pairs of Customers (X, Y) and against each pair, the number of overlapping products. The query should thus have three columns. Order the results by the number of overlapping products.
The question uses the https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_all
database.
Using joins, I can answer the question like this:
O2.CustomerID AS Cust2,
COUNT(*) AS OverlappingProd
FROM (SELECT O.CustomerID, OD.ProductID
FROM Orders AS O
JOIN OrderDetails AS OD
ON OD.orderid = o.orderid) AS O1
JOIN(SELECT O.CustomerID, OD.ProductID
FROM Orders AS O
JOIN OrderDetails AS OD
ON OD.orderid = o.orderid) AS O2
ON O2.ProductID = O1.ProductID
AND O2.CustomerID > O1.CustomerID
GROUP BY
O1.CustomerID,
O2.CustomerID
ORDER BY COUNT(*) DESC;
Is there a way to answer it not using the JOIN function? Thank you for your time and consideration.
I cannot think of a way of doing this without any joins. You can express this in SQL using cross join and exists, so the following comes close:
select c1.customerid, c2.customerid,
(select count(*)
from products p
where exists (select 1
from orderdetails od
where od.productid = p.productid and
exists (select 1
from orders o
where o.orderid = od.orderid and
o.customerid = c1.customerid
)
) and
exists (select 1
from orderdetails od
where od.productid = p.productid and
exists (select 1
from orders o
where o.orderid = od.orderid and
o.customerid = c2.customerid
)
)
) as num_products
from customers c1 cross join
customers c2
where c1.customerid < c2.customerid;
Although this syntax will work in many databases, the nested correlation clauses are not supported in MySQL. So, even accepting the CROSS JOIN, this does not work in MySQL.
The reason why a JOIN seems necessary is to get two independent customer ids in the result set.
Related
I stumbled upon a strange behavior of MySQL (v.8) when trying to run a nested subquery in the FROM clause. The (relevant part of the) schema of the sample database I am using is as follows:
The following two queries run identically on SQL Server:
SELECT SUM(tot) as total
FROM (
SELECT
SUM(OD.quantityOrdered * OD.priceEach) as tot,
C.customerNumber
FROM customers C
INNER JOIN orders O ON C.customerNumber = O.customerNumber
INNER JOIN orderdetails OD ON O.orderNumber = OD.orderNumber
GROUP BY O.orderNumber, C.customerNumber
) AS CO
GROUP BY CO.customerNumber;
and
SELECT
(
SELECT SUM(tot) as total
FROM
(
SELECT
(
SELECT SUM(OD.quantityOrdered * OD.priceEach)
FROM orderdetails OD
WHERE OD.orderNumber = O.orderNumber
) AS tot
FROM orders O
WHERE O.customerNumber = C.customerNumber
) AS ORD
) AS total
FROM customers AS C;
However, on MySQL, the first one runs fine, while the second one results in an error:
Error Code: 1054. Unknown column 'C.customerNumber' in 'where clause'
I will appreciate any clues about why this is happening. Please note that I am mostly interested not in workarounds or other ways to implement this query, but in understanding the reasons why the nested query fails.
C table alias in not in scope for the suquery
try refactoring the query using a join
eg
select c.customerNumber, t.my_tot
FROM customers AS C
INNER JOIN (
SELECT O.customerNumber, SUM(OD.quantityOrdered * OD.priceEach) my_tot
FROM orderdetails OD
INNER JOIN orders O ON OD.orderNumber = O.orderNumber
GROUP BY O.customerNumber
) t on t.customerNumber = c.customerNumber
or
select t.my_tot
FROM customers AS C
INNER JOIN (
SELECT O.customerNumber, SUM(OD.quantityOrdered * OD.priceEach) my_tot
FROM orderdetails OD
INNER JOIN orders O ON OD.orderNumber = O.orderNumber
GROUP BY O.customerNumber
) t on t.customerNumber = c.customerNumber
you can try like below
SELECT
(
select SUM(tot) as total from
(
SELECT
(
SELECT SUM(OD.quantityOrdered * OD.priceEach)
FROM orderdetails OD
WHERE OD.orderNumber = O.orderNumber
) AS tot,customerNumber
FROM orders O
) as ord
WHERE ord.customerNumber = C.customerNumber
) AS total
FROM customers AS C;
Your customers table not in scope of subquery where you used in where condition WHERE O.customerNumber = C.customerNumber so i made alias of that
and then later level i used same condition where customers table has scope
You have a correlated subquery in the second case. However, the correlation clause is two levels deep.
Many databases will still recognize c, even when nested multiple levels. However, MySQL (and Oracle and I think MS Access) is a database that limits correlation clauses to one level deep.
I need to select the customer and product code and the date on which the order was made, but I'm having some trouble with the join orders.
My SQL select:
select c.customerNumber, p.productCode, o.orderDate as data_compra
from customers as c inner join orders as o
inner join products as p
where p.productCode =
any (
select p2.productCode from products as p2
inner join orders as o
inner join orderdetails as odt
where o.orderNumber = odt.orderNumber and
p2.productCode = odt.productCode
)
and o.orderNumber =
any (
select o2.orderNumber from orders as o2
inner join orderdetails as odt
where o.orderNumber = odt.orderNumber and
p.productCode = odt.productCode
)
Two simple joins should do what you want:
select
c.customerNumber,
d.productCode,
o.orderDate
from customer c
join orders o on o.customerNumber = c.customerNumber
join orderdetails d on d.orderNumber = o.orderNumber
In the code you're asking to inner join two tables but not specifying the relationship. You need to do so SQL can relate and match the rows in each table.
You do this with the ON keyword.
I suggest you watch this video and read this article before continuing
Hey guys I have an question that I need some support on.
I am trying to get the top 3 suppliers with a single query from a table.
This is the original question: Who are the top three suppliers by revenue, and where are they located?
Here is the online table and a query you have to run to create a new table.
http://www.w3schools.com/sql/trysql.asp?filename=trysql_select_all
CREATE TABLE ByCustomerOrders AS
SELECT
o.OrderID
, p.ProductName
, p.ProductID
, Price
, Quantity
, Price * Quantity AS subtotal
, c.CustomerID
, s.SupplierID
FROM OrderDetails AS od
LEFT JOIN Orders AS o ON od.OrderID = o.OrderID
LEFT JOIN Products AS p ON p.ProductID = od.ProductID
LEFT JOIN Customers AS c on c.CustomerID = o.CustomerID
LEFT JOIN Suppliers AS s ON s.SupplierID = p.SupplierID;
From that, it creates a new table I need to list just the top 3 suppliers, pretty much the supplierID row value that shows up the most.
Some help would be appreciated.
If you want to get the 3 top suppliers by revenue (and revenue is the sum of all subtotals) this should work:
SELECT s.*, SUM(co.subtotal) as revenue
FROM ByCustomerOrders co
INNER JOIN Suppliers s ON co.SupplierID = s.SupplierID
GROUP BY co.SupplierID
ORDER BY revenue DESC
LIMIT 3;
PS: You should consider using decimal (instead of float or double) for columns that will represent money or you'll get precision errors and your numbers won't add up.
You have a fairly complex schema that you haven't completely disclosed, so this is a guess.
SELECT COUNT(s.SupplierID) AS supplier_count,
SUM(Price * Quantity) AS supplier_subtotal,
s.SupplierID,
s.SupplierName /*this is a guess*/
FROM OrderDetails AS od
LEFT JOIN Orders AS o ON od.OrderID = o.OrderID
LEFT JOIN Products AS p ON p.ProductID = od.ProductID
LEFT JOIN Customers AS c on c.CustomerID = o.CustomerID
LEFT JOIN Suppliers AS s ON s.SupplierID = p.SupplierID
GROUP BY s.SupplierID, s.SupplierName
ORDER BY COUNT(s.SupplierID) DESC
LIMIT 3
This should give you the top suppliers (by units ordered).
The trick here is to use an aggregate query (SUM() ... GROUP BY) and then order by one of the aggregate values with a DESCending qualifier.
You might want to troubleshoot this query by leaving off the LIMIT clause until you're sure you're getting the right information.
//Personal understanding, not a hw assignment
So in the sample db northwind from MS there are the tables: orders o, [order details] od, customers c
o has orderID, customerID (inc. duplicates)
od has orderID (inc. duplicates), unitprice, quantity, discount
c has customerID, companyName
roughly speaking,
I want to join on
o.customerID = c.customerID; selecting companyName ///
join on o.orderID = od.orderID; selecting unitprice, quantity, discount
my end goal is to
sum(q (up - d)) AS 'Order Total' group by od.orderID then
sum(Order Total) group by companyName(?)
My main issue is not know how/what to join properly though.
Thanks in advance
Check out your scenario on SQL Fiddle
SELECT comp.`company_name` AS 'company',COUNT(DISTINCT o.id_sales_order) AS 'total_orders',SUM(`unit_price`) AS 'grand_total'
FROM sales_order AS o
LEFT JOIN sales_order_item AS od ON od.fk_sales_order = o.id_sales_order
LEFT JOIN customer AS c ON c.id_customer = o.fk_customer
LEFT JOIN company AS comp ON comp.id_company = c.fk_company_id
GROUP BY comp.`company_name`
hope this what you are looking for
Assuming that you create the correct Select statement as you required, the join part should be something like:
From Orders o join Order_Detail od on o.orderID = od.orderID
join Customer c on o.customerID = c.customerID
Types of join can be: join, inner join, right/left join. It depends on you what do you want to achive i.e if you want to exclude/include null references. But the structure is the same.
i need little help in writing the MYSQL Query.
i want to retreive the data from 3 tables, but i want to retreive the data from 3rd table only if the count() value is equals to 1.
please see the below query.
SELECT count(orderdetails.orderId) as total,gadgets.*,orders.* FROM orders
JOIN orderdetails ON orders.orderId = orderdetails.orderId
CASE total WHEN 1 THEN (JOIN gadgets ON gadgets.gadgetId = orders.gadgetId)
GROUP BY orders.orderId
ORDER BY orders.orderId DESC;
mysql always gives me an error, and i couldnt find any solution over internet.
Just add a Simple Condition in Join, and it would work (Of course you have make it Left Join).
SELECT count(orderdetails.orderId) as total,gadgets.*,orders.* FROM orders
JOIN orderdetails ON orders.orderId = orderdetails.orderId
LEFT JOIN gadgets ON gadgets.gadgetId = orders.gadgetId
and total=1 --Simple Logic
GROUP BY orders.orderId
ORDER BY orders.orderId DESC;
SELECT
g.*, o.*
FROM
orders AS o
JOIN
( SELECT orderId
FROM orderdetails
GROUP BY orderId
HAVING COUNT(*) = 1
) AS od
ON o.orderId = od.orderId
JOIN gadgets AS g
ON g.gadgetId = o.gadgetId
ORDER BY
o.orderId DESC ;
You can join the table and get only results having total = 1
SELECT count(orderdetails.orderId) as total,gadgets.*,orders.* FROM orders
JOIN orderdetails ON orders.orderId = orderdetails.orderId
JOIN gadgets ON gadgets.gadgetId = orders.gadgetId
GROUP BY orders.orderId
HAVING total = 1
ORDER BY orders.orderId DESC;
HTH