SELECT a column and SUM() of values from another table in SQL - mysql

I'm pretty new with SQL, and this is giving me trouble. The idea is that I have several tables. Here are the relevant tables and columns:
customers:
customer_id, customer_name
orders:
order_id, customer_id
orderline:
order_id, item_id, order_qty
items:
item_id, unit_price
I need to return customer_name as well as total revenue from that customer (calculated as item_price * order_qty * 2).
Here's what I have written:
SELECT customers.customer_name, sum(revenue)
FROM SELECT orderline.order_qty * items.unit_value * 2 AS revenue
FROM orderline
INNER JOIN orders
ON orderline.order_id = orders.order_id
INNER JOIN customers
ON revenue.customer_id = customers.customer_id;
This throws a syntax error and I'm not really sure how to proceed.
This is only one example of this type of problem that I need to work out, so more generalized answers would be helpful.
Thanks in advance!
EDIT:
With help from answers I ended up with this code, which just gets total revenue and puts it next to the first person in the DB's name. What did I get wrong here?
SELECT customers.customer_name, sum(revenue)
FROM(SELECT orderline.order_qty * items.unit_price * 2 AS revenue, orders.customer_id AS CustomerID
FROM( orderline
INNER JOIN orders
ON orderline.order_id = orders.order_id
INNER JOIN items
ON orderline.item_id = items.item_id)) CustomerOrders
INNER JOIN customers
ON CustomerOrders.CustomerID = customers.customer_id;

A couple issues with your query.
First, you need to scope your subquery and alias it:
(SELECT orderline.order_qty * items.unit_value * 2 AS revenue
FROM orderline
INNER JOIN orders
ON orderline.order_id = orders.order_id) CustomerOrders
Secondly, you need to select more than the revenue in the subquery since you are joining it to your customers table
(SELECT
orderline.order_qty * items.unit_value * 2 AS revenue,
orders.customer_id AS CustomerId
FROM
orderline
INNER JOIN orders ON orderline.order_id = orders.order_id) CustomerOrders
Then you need to use the subquery alias in the join to the customers table and wrap it all up in a group by customer_id and CustomerOrders.Revenue
I would tend to do it differently. I'd start with selecting from the customer table, because that is the base of what you are looking for. Then I'd do a cross apply on the orders that would all aggregating the order revenue in the subquery. It would look like this (tsql, you could do the same in mysql with a join with some aggregation):
SELECT
customers.customer_name,
ISNULL(customerOrders.Revenue, 0) AS Revenue
FROM
customers
OUTER APPLY (
SELECT
SUM (orderline.order_qty * items.unit_value * 2) AS Revenue
FROM
orders
INNER JOIN
orderline ON orders.order_id = orderline.order_id
INNER JOIN
items on orderline.item_id = items.item_id
WHERE
orders.customer_id = customers.customer_id
) CustomerOrders
In this case, the subquery aggregates all your orders for you and only returns one row per customer, so no extraneous returned data. Since it's an outer apply, it will also return null for customers with no orders. You could change it to a CROSS APPLY and it will filter out customers with no orders (like an INNER JOIN).

SELECT c.customer_name,
sum(COALESCE(ol.order_qty,0) * COALESCE(i.unit_value,0) * 2)
FROM customers c
INNER JOIN orders o
ON o.customer_id = c.customer_id;
INNER JOIN orderline ol
ON ol.order_id = o.order_id
INNER JOIN items i
ON i.item_id = ol.item_id
GROUP BY c.customer_id

select customer_name, sum(item_price * order_qty * 2) as total_revenue
from (
select * from customers
inner join orders using(customer_id)
inner join orderline using(order_id)
inner join items using(item_id)
)
group by customer_name

select
c.customer_name,
r.revenue
from
customers c
inner join
orders ord on
ord.customer_id = c.customer_id
inner join
(select i.item_id, o.order_id, sum(o.order_qty * items.unit_value * 2) as revenue
from orderline o
inner join items i on
i.item_id = o.item_id
group by o.order_id, i.item_id) as r on r.order_id = o.order_id

Related

The output of MySQL results shows no results in one column

Whenever I use this query:
SELECT Orders.SKU AS SKU,
(COUNT(*) * 100 / (SELECT COUNT(*) FROM Orders INNER JOIN RMA ON Orders.OrderID = RMA.OrderID)) AS Returned_Percentage
FROM Orders
INNER JOIN RMA
ON Orders.OrderID = RMA.OrderID
INNER JOIN Customers
ON Customers.CustomerID = Orders.CustomerID
GROUP BY SKU, Description
ORDER BY Returned_Percentage DESC
I get the results that I need.
Successful Results
But when I add a column with a larger VARCHAR(50), the results leave out one column of results.
SELECT Orders.SKU AS SKU,
(COUNT(*) * 100 / (SELECT COUNT(*) FROM Orders INNER JOIN RMA ON Orders.OrderID = RMA.OrderID)) AS Returned_Percentage, **Orders.Description**
FROM Orders
INNER JOIN RMA
ON Orders.OrderID = RMA.OrderID
INNER JOIN Customers
ON Customers.CustomerID = Orders.CustomerID
GROUP BY SKU, Description
ORDER BY Returned_Percentage DESC
enter image description here
Can anyone point me in the right direction to obtaining the results with the records stored properly in the columns?
Thank you!
I add the query:
SELECT Orders.SKU AS SKU,
(COUNT(*) * 100 / (SELECT COUNT(*) FROM Orders INNER JOIN RMA ON Orders.OrderID = RMA.OrderID)) AS Returned_Percentage, Orders.Description
FROM Orders
INNER JOIN RMA
ON Orders.OrderID = RMA.OrderID
INNER JOIN Customers
ON Customers.CustomerID = Orders.CustomerID
GROUP BY SKU, Description
ORDER BY Returned_Percentage DESC
but receive empty columns of records.

MySQL not returning values from NOT IN function

I currently am trying to write a query that shows customers with at least 5 orders and customer with no orders. Orders are tracked in their own table and in order to find customers with 0 orders we have to find the customers NOT IN orders. Below is my query I'm trying to use and it returns the same customer 5 times for zero orders.
with t1 as
(select o.customerNumber, c.customerName, count(o.orderNumber) as FiveOrders
from orders o join customers c on (o.customerNumber = c.customerNumber)
group by o.customerNumber having count(o.orderNumber) = 5),
t2 as
(select distinct o.customerNumber, c.customerName, count(o.orderNumber) as NoOrders
from orders o join customers c on (o.customerNumber = c.customerNumber)
group by c.customerNumber not in(select customerNumber from orders))
select distinct t1.customerNumber as FiveOrderNumber, t1.customerName as FiveOrderName,
t2.customerNumber as NoOrderNumber, t2.customerName as NoOrderName
from t1 join t2
order by NoOrderName;
Any and all help is appreciated thanks!
If the errors were only in the second table to, I think it is after using
having with condition NOT IN without any logical comparison, I think you can get wanted results easily like:
select distinct customerNumber, customerName, "0" as NoOrders
from customers
where customerNumber not in (Select customerNumber from orders)
If the group by is important, you can use it like in your code.
Zero or five could be counted together with LEFT JOIN
select c.customerNumber, max(c.customerName) customerName, count(o.orderNumber) as FiveOrdersOrZero
from customers c
left join orders o on o.customerNumber = c.customerNumber
group by c.customerNumber
having count(o.orderNumber) in ( 0, 5 )
order by FiveOrdersOrZero

Combining two queries and getting the sum of count

I have two different queries that each do half the job I need. how to combine them.
orders table has orderNumber and customerNumber, customers table has customerNumber and salesRepEmployeeNumber, orderdetails has multiple lines of the same orderNumber each showing price&quantity of different items).
(counting the number of orders from different customers each sales rep has)
select c.salesRepEmployeeNumber, count(*)
from customers c
inner join orders o1
on c.customerNumber = o1.customerNumber
group by c.salesRepEmployeeNumber;
and
(counting the revenue made by each sales rep)
select c.salesRepEmployeeNumber, sum(o2.priceEach*o2.quantityOrdered) as "Revenue"
from customers c
inner join orders o1
on c.customerNumber = o1.customerNumber
inner join orderdetails o2
on o1.orderNumber = o2.orderNumber
group by c.salesRepEmployeeNumber;
I need a query to know the employee number, # of orders, and revenue. I tried
select sum(o2.priceEach*o2.quantityOrdered) as "Revenue", c.salesRepEmployeeNumber, count(*)
from customers c
inner join orders o1
on c.customerNumber = o1.customerNumber
inner join orderdetails o2
on o1.orderNumber = o2.orderNumber
group by c.salesRepEmployeeNumber;
but it returns the count of items/products from the orders (e.g. 1 order has three products)
SELECT salesRepEmployeeNumber,
t1.`count(*)` AS `count`,
t2.Revenue
FROM (complete text of 1st query) AS t1
LEFT JOIN (complete text of 2nd query) AS t2 USING (salesRepEmployeeNumber)
complete text means "without final semicolon".
If your data guarantees that the amount of rows produced by 2nd query is equal to one produced by 1st query then you may use not LEFT but INNER joining.
Also test
select c.salesRepEmployeeNumber
, COUNT(DISTINCT o1.id) AS orders_count
, sum(o2.priceEach*o2.quantityOrdered) as "Revenue"
from customers c
join orders o1
on c.customerNumber = o1.customerNumber
join orderdetails o2
on o1.orderNumber = o2.orderNumber
group
by c.salesRepEmployeeNumber;
where o1.id is primary key expression (or any unique non-NULL column/expression/index) of orders table.

Why SQL Displays Two Rows Instead of One

Here is the Query
SELECT o.OrderID, o.CNIC,
(SELECT FullName FROM Customer WHERE CNIC=o.CNIC) Customer,
o.Date
FROM orders o
JOIN ordersproduct op ON op.OrderID=o.OrderID
WHERE o.OrderID=1;
Here is the result
1 - 15604-5566123-2 - Shaiz Mehran - 2020-09-30
1 - 15604-5566123-2 - Shaiz Mehran - 2020-09-30
If the purpose is to only show customers who has an order, but no details of the orderproduct itself you could use the following :
SELECT DISTINCT o.OrderID, o.CNIC,
(SELECT FullName FROM Customer WHERE CNIC=o.CNIC) Customer,
o.Date
FROM orders o
WHERE o.OrderID=1;
OR
SELECT DISTINCT o.OrderID, o.CNIC,
c.Customer, o.Date
FROM orders o
INNER JOIN Customer c ON c.CNIC = o.CNIC
WHERE o.OrderID=1;
If this is only the start and you will show the product which the customer ordered it will show two rows as the customer has two products (orderproducts). This will return two rows with different orderproducts
SELECT DISTINCT o.OrderID, o.CNIC,
c.Customer, o.Date op.ColumnTosShow
FROM orders o
INNER JOIN Customer c ON c.CNIC = o.CNIC
INNER JOIN ordersproduct op ON op.OrderID=o.OrderID
WHERE o.OrderID=1;
SELECT Distinct Orders.OrderID, Orders.CNIC, Customer.FullName
FROM (Orders LEFT JOIN Customer ON Orders.CNIC = Customer.CNIC)
LEFT JOIN OrdersProduct ON Orders.OrderID = OrdersProduct.OrderID;
The reason you are getting multiple rows is because an order can have multiple products . . . and you are getting one row per product.
The join to the product table seems quite unnecessary, so just use:
SELECT o.OrderID, o.CNIC,
(SELECT FullName FROM Customer WHERE CNIC=o.CNIC) as Customer,
o.Date
FROM orders o
WHERE o.OrderID = 1;
I am guessing you have a reasonable data model so there are not multiple rows in orders for a given id. SELECT DISTINCT is not necessary.
I should add that JOIN is very reasonable for this query, but like this:
SELECT o.OrderID, o.CNIC, c.FullName as Customer,
o.Date
FROM orders o LEFT JOIN
customer c
ON o.CNIC = c.CNIC
WHERE o.OrderID = 1;

MySQL: Ranking from multiple tables, sub queries?

This is a MySQL question. I have three tables with the following columns:
transactions (table): transact_id, customer_id, transact_amt, product_id,
products (table): product_id, product_cost, product_name, product_category
customers (table): customer_id, joined_at, last_login_at, state, name, email
I'd like a query that finds out the most popular item in every state and the state. One of the tricky parts is that some product_name have multiple product_id. Therefore I though joining the three tables that generate an output with two columns: state and product_name. Until here that worked fine doing this:
SELECT p.product_name, c.state
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
This selects all the products, and the states from where the customer is. The problem is that I can't find the way to rank the mos popular product per state. I tried different group by, order by and using subqueries without success. I suspect I need to do subqueries, but I can't find the way to resolve it. The expected outcome should look like this:
most_popular_product | state
Bamboo | WA
Walnut | MO
Any help will be greatly appreciated.
Thank you!
You need a subquery that gets the count of transactions for each product in each state.
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
Then write another query that has this as a subquery, and gets the highest count for each state.
SELECT state, MAX(count) AS maxcount
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t
GROUP BY state
Finally, join them together:
SELECT t1.product_name AS most_popular_product, t1.state
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t1
JOIN (
SELECT state, MAX(count) AS maxcount
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t
GROUP BY state
) AS t2 ON t1.state = t2.state AND t1.count = t2.maxcount
This is basically the same pattern as SQL select only rows with max value on a column, just using the first grouped query as the table you're trying to group.