Finding the city in which the most orders were sent leads to the assignment of the city and the number of orders (the named amount column). I have 2 tables the named Customers and Orders
SELECT Customers.City,count( Orders.OrderID) as amount
FROM voodoo.Customers
inner join voodoo.Orders on Customers.CustomerID=Orders.CustomerID
group by Customers.City
having amount >= all(select count(Orders.OrderID)
from voodoo.Customers
inner join voodoo.Orders on Customers.CustomerID=Orders.CustomerID
group by Customers.City);
tables
You don't need a subquery as you can just order by amount (descending) and limit the result to 1:
SELECT Customers.City, count(Orders.OrderID) as amount
FROM voodoo.Customers INNER JOIN voodoo.Orders
ON Customers.CustomerID=Orders.CustomerID
GROUP BY Orders.OrderID
ORDER BY amount DESC
LIMIT 1;
EDIT: as Thorsten Kettner pointed out, I made a copy & paste error; the correct version would GROUP BY Customers.City.
You are looking for the order count per city, not per order. So, don't group by order, but by city. For the ranking of the cities you can use RANK or DENSE_RANK.
SELECT city, amount
FROM
(
SELECT
c.city,
COUNT(o.orderid) AS amount,
RANK() OVER (ORDER BY COUNT(o.orderid) DESC) AS rnk
FROM voodoo.customers c
INNER JOIN voodoo.orders o ON o.customerid = c.customerid
group by c.city
) counted_and_ranked
WHERE rnk = 1;
Related
I need a database with two tabels. I need to JOIN them, group the records and then display top 5 rows from each group. Here is my initial query without top N records:
SELECT customerId, itemId, count(itemId) as num FROM Orders JOIN OrderItems ON orderId=orderId ORDER BY num DESC GROUP BY customerId
I suppose I would need a ROWNUM and PARTITION BY here, but I have no idea how to combine them with JOIN tables. Could you please help me?
To retrieve the top 5 rows per group in your query, you can use a subquery with the ROW_NUMBER function and a PARTITION BY clause.
SELECT customerId, itemId, num
FROM (
SELECT customerId, itemId, num,
ROW_NUMBER() OVER (PARTITION BY customerId ORDER BY num DESC) as rn
FROM (
SELECT customerId, itemId, count(itemId) as num
FROM Orders
JOIN OrderItems ON Orders.orderId = OrderItems.orderId
GROUP BY customerId, itemId
) as subquery1
) as subquery2
WHERE rn <= 5;
If you want to display the 5 orders with the most items, you could use this:
SELECT TOP 5
o.orderID, count(*)
FROM Order o INNER JOIN OrderItem oi on o.OrderID = oi.OrderID
GROUP BY o.OrderID
ORDER BY count(*) DESC
For displaying the top 5 items in each order, it is a bit more complex, because you cannot use windowed functions in WHERE or ORDER BY.
For this, you need a subquery to retrieve the ranking and sort/filter the result.
SELECT *
FROM
(
SELECT
oi.*,
ROW_NUMBER() OVER (PARTITION BY oi.OrderID ORDER BY oi.Something) as ranking
FROM OrderItem oi
) tmp WHERE ranking < 6
ORDER BY tmp.OrderID, tmp.ranking
If that is not your intent, please give an example for your intended result.
There are 2 tables customer (id, name) and orders (id, customer_id, date, price) where customer_id is the foreign key.
How would one get the top 5 individuals with the most purchases in the last 6 months?
needed output format is (customer.id, customer.name, sum(price))
select c.id, c.name, SUM(o.price) as total
from customer c inner join orders o
on c.id = o.customer_id
order by total desc limit 5;
I'm not sure why this query I have doesn't display anything
SUM() is an aggregate function that calculates the sum after a grouping operation. Try using a GROUP BY clause like this:
select c.id, c.name, SUM(o.price) as total
from customer c inner join orders o
on c.id = o.customer_id
group by c.id, c.name
order by total desc limit 5;
DB-fiddle: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=7f5e3726d6af5a9144a03d503da5ae37
I have this schema here, and I need to find the name of the customer with the highest total amount for the orders. I have a SQL query here:
SELECT Name
FROM (SELECT Name, SUM(Amount) AS Total
FROM customer JOIN orders ON cust_id = ID
GROUP BY Name) AS Totals
WHERE Total = (SELECT MAX(Total)
FROM (SELECT Name, SUM(Amount) AS Total
FROM customer JOIN orders ON cust_id = ID
GROUP BY Name) AS X);
But this is very inefficient as it creates the same table twice. Is there any more efficient way to get the name?
If you want customer with the greatest total mount, then you can just join, order by and limit:
select c.name
from customer c
inner join orders o on o.cust_id = c.id
group by c.id, c.name
order by sum(o.amount) desc
limit 1
Note that this does not handle possible top ties. For this, you need a little more code. Instead of ordering, you would typically filter with a having clause:
select c.name
from customer c
inner join orders o on o.cust_id = c.id
group by c.id, c.name
having sum(o.amount) = (
select sum(o1.amount)
from orders o1
group by cust_id
order by sum(o1.amount) desc
limit 1
)
Finally: if you are running MySQL 8.0, this is simpler done with window function rank():
select name
from (
select c.name, rank() over(order by sum(o.amount) desc) rn
from customer c
inner join orders o on o.cust_id = c.id
group by c.id, c.name
) t
where rn = 1
I need to write a query to find the youngest customer who bought atleast 1 product
Here is the data:
CUSTOMER:
ORDER_DETAIL:
This is my query so far:
SELECT c.CUSTOMERID, c.age, c.name
from (
SELECT CUSTOMERID, COUNT(ORDERID) as "totalOrder"
FROM FACEBOOK_ORDER_DETAIL
GROUP BY CUSTOMERID
HAVING COUNT(ORDERID) >=1) AS tbl
LEFT JOIN FACEBOOK_CUSTOMER c on c.CUSTOMERID = tbl.CUSTOMERID
order by c.age ;
However, above query gives me
But I need the list of customers with the minimum age.
If you really only want a single youngest customer, even should there be a tie, then use LIMIT:
SELECT c.CUSTOMERID, c.age, c.name
FROM CUSTOMER c
INNER JOIN FACEBOOK_ORDER_DETAIL o
ON c.CUSTOMERID = c.CUSTOMERID
ORDER BY
c.age
LIMIT 1;
This should work because if a customer joins to the order details table, it implies that he had at least one order.
If instead you want to find all youngest customers, including all ties, then a nice way to handle this uses the RANK analytic function:
SELECT DISTINCT CUSTOMERID, age, name
FROM
(
SELECT c.CUSTOMERID, c.age, c.name, RANK() OVER (ORDER BY c.age) rnk
FROM CUSTOMER c
INNER JOIN FACEBOOK_ORDER_DETAIL o
ON c.CUSTOMERID = o.CUSTOMERID
) t
WHERE rnk = 1;
Demo
For earlier versions of MySQL, we can use a subquery as a workaround for not having RANK:
SELECT DISTINCT c.CUSTOMERID, c.age, c.name
FROM CUSTOMER c
INNER JOIN FACEBOOK_ORDER_DETAIL o
ON c.CUSTOMERID = c.CUSTOMERID
WHERE c.age = (SELECT MIN(t1.age)
FROM CUSTOMER t1
INNER JOIN FACEBOOK_ORDER_DETAIL t2
ON t1.CUSTOMERID = t2.CUSTOMERID);
Demo
You only want columns from customers, so I would phrase this as:
select c.*
from (select c.*,
rank() over (order by age) as seqnum
from customers c
where exists (select 1
from facebook_order_detail fod
where fod.customerid = c.customerid
)
) c
where seqnum = 1;
In particular, this requires no duplicate elimination or aggregation, so it should be faster. And it can use an index on face_book_details(customerid) and also perhaps on customers(age, customerid).
Im trying to get by subquery clientId of customer with most orders but only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
SELECT a.ClientName
FROM Clients as a
INNER JOIN Orders as b
ON a.Id=b.ClientId
WHERE b.ClientId
IN(SELECT b.ClientId,COUNT( b.ClientId) as MAKS FROM Orders as b
GROUP BY b.ClientId ORDER BY MAKS DESC)
Do we have some tools to handle this and how can i optimize this query? Thanks in advance.
You don't really need the inner join because you are asking for an ID that is the same in both tables,
SELECT ClientName FROM Clients
WHERE Id = (SELECT TOP 1 ClientId FROM Orders
GROUP BY ClientId
ORDER BY COUNT(ClientId) DESC)
Using Top 1, Count and Group By
SQL Server
SELECT Top 1 a.ClientName , count(b.orders_id) TotalOrders
FROM Clients as a
INNER JOIN Orders as b
ON a.Id=b.ClientId
GROUP BY a.client_name
order by TotalOrders desc
MySQL
SELECT a.ClientName , count(b.orders_id) TotalOrders
FROM Clients as a
INNER JOIN Orders as b
ON a.Id=b.ClientId
GROUP BY a.client_name
order by TotalOrders desc
LIMIT 1