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.
Related
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
I am practicing MYSQL using https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_func_mysql_concat which has a mock database for me to practice with an I am experimenting using the GROUP BY command I am attempting to group all employees up with all of their sales and determine, their name, their amount of sales and the product that they sold the most. I have managed to get their name and sales but not the product name. I know that extracting information with a group by is difficult and I have tried using a sub query. Is there a way to get the information.
My query is below.
SELECT
CONCAT_WS(' ',
Employees.FirstName,
Employees.LastName) AS 'Employee name',
COUNT(*) AS 'Num of sales'
FROM
Orders
INNER JOIN
Employees ON Orders.EmployeeID = Employees.EmployeeID
INNER JOIN
OrderDetails ON OrderDetails.OrderID = Orders.OrderID
INNER JOIN
Products ON Products.ProductID = OrderDetails.ProductID
GROUP BY Orders.EmployeeID
ORDER BY COUNT(*) DESC;
What this says is get orders, join employees based on orders employeeid, join the order details based on order id and join products information based on product id in the order details, then it groups them by the employee id and orders them by the number of sales an employee has made.
SELECT
concat_ws(' ',
Employees.FirstName,
Employees.LastName) as 'Employee name',
count(*) as 'Num of sales',
(
SELECT Products.ProductName
FROM Orders
INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID
INNER JOIN OrderDetails ON OrderDetails.OrderID = Orders.OrderID
INNER JOIN Products ON Products.ProductID = OrderDetails.ProductID
GROUP BY Orders.EmployeeID
ORDER BY count(Products.ProductName) desc
LIMIT 1
) as 'Product Name'
FROM Orders
INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID
INNER JOIN OrderDetails ON OrderDetails.OrderID = Orders.OrderID
INNER JOIN Products ON Products.ProductID = OrderDetails.ProductID
GROUP BY Orders.EmployeeID
ORDER BY count(*) desc;
Above is my attempt at using a sub query for the solution.
It is quite ugly, as the w3school uses still mysql 5.7
On a personal note, you should install your own server grab somewhere a database and test it there, in mysql workbench you can have many query tabs in which you can test queries , till you het the "right" result.
SELECT
CONCAT_WS(' ',
Employees.FirstName,
Employees.LastName) AS 'Employee name',
COUNT(*) AS 'Num of sales',
tn.ProductName
FROM
Orders
INNER JOIN
Employees ON Orders.EmployeeID = Employees.EmployeeID
INNER JOIN
OrderDetails ON OrderDetails.OrderID = Orders.OrderID
INNER JOIN
Products ON Products.ProductID = OrderDetails.ProductID
INNEr JOIN
(SELECT EmployeeID, p.ProductName
FROM (SELECT IF (#Eid = EmployeeID ,#rn := #rn +1, #rn := 1) rn,ProductID, sumamount
, #Eid := EmployeeID as EmployeeID
FROM
(
SELECT
EmployeeID,ProductID, SUM(Quantity) sumamount
FROM Orders o INNER JOIN OrderDetails od ON od.OrderID = o.OrderID,(SELECT #Eid := 0, #rn := 0) t1
GROUP BY EmployeeID,ProductID
ORDER BY EmployeeID,sumamount DESC ) t2 ) t3
INNER JOIN Products p ON t3.ProductID = p.ProductID
WHERE rn= 1) tn
ON Orders.EmployeeID = tn.EmployeeID
GROUP BY Orders.EmployeeID
ORDER BY COUNT(*) DESC;
In your second query you are trying to get an employee's most often sold product. But there are two mistakes in that subquery:
The subquery is invalid. You group by employee, but select a product. Which product? An employee can sell many different products. MySQL should raise a syntax error here, as all other DBMS I know of do. But you are in cheat mode. MySQL allows incorrect aggregation queries and silently applies ANY_VALUE on all columns that cannot be selected otherwise. Thus you are selecting ANY_VALUE(Products.ProductName), i.e. a product arbitrarily chosen by the DBMS. To get out of cheat mode SET sql_mode = 'ONLY_FULL_GROUP_BY';.
Then, you don't relate the subquery to your main query. So when selecting the row for, say, employee #123, your subquery still selects data for all employees in order to pick one of their products. And as this is independent from the employee in the main query, it will probably pick the same product for every other employee you are selecting, too.
Here is what the query should look like instead:
SELECT
concat_ws(' ', e.FirstName, e.LastName) as "Employee name",
count(*) as "Num of sales",
(
SELECT p2.ProductName
FROM Orders o2
INNER JOIN OrderDetails od2 ON od2.OrderID = o2.OrderID
INNER JOIN Products p2 ON p2.ProductID = od2.ProductID
WHERE o2.EmployeeID = o.EmployeeID
GROUP BY p2.ProductID
ORDER BY count(*) DESC
LIMIT 1
) as "Product Name"
FROM Orders o
INNER JOIN Employees e ON o.EmployeeID = e.EmployeeID
INNER JOIN OrderDetails od ON od.OrderID = o.OrderID
GROUP BY o.EmployeeID
ORDER BY count(*) desc;
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=f35e96764d454a4032d7778b550fc6b4
Disclaimer: When an employee sold more than one product most often (e.g. 500 x product A, 500 x product B, 200 x product C), then one of them (A or B in the example) gets picked arbitrarily for the employee.
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;
I'm trying to calculate the total purchase amount of each customer from the database available online on W3 Schools
The tables I'm using are:
Customers
Orders
Products
OrderDetails
My current query gives me the product wise purchase amount for the customer. What I need is the total purchase amount.
SELECT c.CustomerID,o.OrderID,(ord.Quantity*p.Price) as
Total_Amount
from Customers c inner join Orders o
inner join Products p
inner join OrderDetails ord
on c.CustomerID = o.CustomerID
and o.OrderID = ord.OrderID
and ord.ProductID = p.ProductID;
My Output:
I need the sum for the values with the same order id and customer id.
I tried out group-by and sum but it gives me the overall sum of all the products.
You simply want a GROUP BY:
SELECT c.CustomerID, SUM(ord.Quantity*p.Price) as
Total_Amount
FROM Customers c inner join Orders o
on c.CustomerID = o.CustomerID join
OrderDetails ord
on o.OrderID = ord.OrderID join
Products p
on ord.ProductID = p.ProductID
GROUP BY CustomerID;
Note that this orders the JOINs so the ON clauses are interleaved. This is how JOINs are normally written.
If you need the sum for the values with the same order id and customer id, then you need to group the rows based on both customer id and order id.
SELECT c.CustomerID,o.OrderID,SUM(ord.Quantity*p.Price) as Total_Amount
from Customers c inner join Orders o
inner join Products p
inner join OrderDetails ord
on c.CustomerID = o.CustomerID
and o.OrderID = ord.OrderID
and ord.ProductID = p.ProductID
Group By c.CustomerID,o.OrderID
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