SQL get total amount of Column with group by? - sql

Below you can see my SQL query
select c.email_address,o.order_id as "Number of Orders",
((oi.item_price-oi.discount_amount)*oi.quantity) as "Total amount"
from customers c
inner join orders o on c.customer_id=o.customer_id
inner join order_items oi on o.order_id=oi.order_id
From that, I can get output like below
Email Orders_id Amount
allan#yahoo.com 1 839.3
barryz#gmail.com 2 303.79
allan#yahoo.com 3 1208.16
allan#yahoo.com 3 253.15
chrisb#gmail.com 4 1678.6
david#hotmail.com 5 299
erinv#gmail.com 6 299
frank#gmail.com 7 489.3
frank#gmail.com 7 559.9
frank#gmail.com 7 489.99
garyz#yahoo.com 8 679.99
david#hotmail.com 9 489.3
But I want to customize it like below
Email Number of Orders Total Amount
allan#yahoo.com 3 2300.61
barryz#gmail.com 1 303.79
chrisb#gmail.com 1 1678.6
david#hotmail.com 2 788.3
erinv#gmail.com 1 299
frank#gmail.com 3 1539.19
garyz#yahoo.com 1 679.99
Can anyone help me to do this?

As you said in the question, use GROUP BY and aggregate the number of orders and the total:
select c.email_address,
COUNT(o.order_id) as "Number of Orders",
SUM((oi.item_price-oi.discount_amount)*oi.quantity) as "Total amount"
from customers c
inner join orders o on c.customer_id=o.customer_id
inner join order_items oi on o.order_id=oi.order_id
GROUP BY c.email_address

You can wrap your query:
select email_address, count("Number of Orders") as number_of_orders, sum("Total Amount") as amount
from (
select c.email_address,o.order_id as "Number of Orders",
((oi.item_price-oi.discount_amount)*oi.quantity) as "Total amount"
from customers c
inner join orders o on c.customer_id=o.customer_id
inner join order_items oi on o.order_id=oi.order_id
)Z
group by email

Related

multiple two column values with grouping by a column

I've two tables tblOrder and tblOrderDetails. I want to get order no, total price per order (Quantity*UnitCost) and OrderDate as given below.
Order No
Total
OrderDate
ORD 1
3000
01/01/2021
ORD 2
2750
01/03/2021
What I've tried is giving me quantity is not a part of aggregate function.
SELECT tblOrder.OrderNo, tblOrderDetails.UnitCost*tblOrderDetails.Quantity AS Total, OrderDate
FROM tblOrderDetails INNER JOIN tblOrder ON tblOrderDetails.OrderId = tblOrder .OrderId
GROUP BY tblOrder.OrderNo;
Table structures and data
Table tblOrder:
OrderId
OrderNo
OrderDate
1
ORD 1
01/01/2021
2
ORD 2
01/03/2021
Table tblOrderDetails:
OrderDetailId
Quantity
UnitCost
OrderId
1
100
30
1
2
50
40
2
2
10
15
2
2
20
30
2
select o.OrderNo
,od.total
,o.OrderDate
from
(
select OrderId
,sum(Quantity*UnitCost) as total
from tblOrderDetails
group by OrderId
) od join tblOrder o on o.OrderId = od.OrderId
OrderNo
total
OrderDate
ORD 1
3000
2021-01-01
ORD 2
2750
2021-01-03
Fiddle
Your requirements are not 100% clear, but maybe, you can just do this, without any subquery:
SELECT tblOrder.OrderNo,
SUM(tblOrderDetails.UnitCost*tblOrderDetails.Quantity) AS Total,
OrderDate
FROM tblOrderDetails
INNER JOIN tblOrder ON tblOrderDetails.OrderId = tblOrder.OrderId
GROUP BY tblOrder.OrderNo,OrderDate;
To see the difference to Danny's answer - which might also be fine - have a look here: db<>fiddle

SQL Query to get value of recent order alongwith data from other tables

I am writing an SQL query to get data from more than 3 tables, but for simplifying the question here I am using a similar scenario with 3 tables.
Table1 Customer (PK-CustomerID, Name)
CustomerID
Name
1
John
2
Tina
3
Sam
Table2 Sales (FK-Id, SalePrice)
ID
SalePrice
1
200.00
2
300.00
3
400.00
Table3 Order (PK-Id, FK-CustomerID, Date, Amount)
Id
CustomerID
Date
Amount
101
1
25-09-2021
30.0
102
1
27-09-2021
40.0
103
2
19-09-2021
60.0
In the output, Date and Amount should be the from most recent Order (latest Date), for a customer
My approach was
Select c.CustomerID, c.Name, s.SalePrice, RecentOrder.Date, RecentOrder.Amount from
Customer as c
LEFT JOIN Sales s ON c.CustomerID = s.ID
LEFT JOIN (SELECT top 1 o.Date, o.Amount, o.CustomerID
FROM Order o, Customer c1 WHERE c1.CustomerID = o.CustomerID ORDER BY o.Date DESC)
RecentOrder ON c.CustomerID = RecentOrder.CustomerID
Output I get
CustomerID, Name, SalePrice, Date, Amount
CustomerID
Name
SalePrice
Date
Amount
1
John
200.00
27-09-2021
40.0
2
Tina
300.00
null
null
3
Sam
400.00
null
null
The output I get includes the most recent order out of all the orders. But I want to get the recent order out of the orders made by that customer
Output Required
CustomerID, Name, SalePrice, Date, Amount
CustomerID
Name
SalePrice
Date
Amount
1
John
200.00
27-09-2021
40.0
2
Tina
300.00
19-09-2021
60.0
3
Sam
400.00
null
null
Instead of subquery in left join, you can check with outer apply.
Check following way
Select c.CustomerID, c.Name, s.SalePrice, RecentOrder.Date, RecentOrder.Amount
from Customer c
LEFT JOIN Sales s ON c.CustomerID = s.ID
OUTER APPLY (
SELECT top 1 o.Date, o.Amount, o.CustomerID
FROM [Order] o
WHERE o.CustomerID = c.CustomerID ORDER BY o.Date DESC) RecentOrder`
You need to pre-aggregate or identify the most recent order for each customer order, your query is selecting 1 row for all orders.
Try the following (untested!)
select c.CustomerID, c.Name, s.SalePrice, o.Date, o.Amount
from Customer c
left join Sales s on c.CustomerID = s.ID
outer apply (
select top (1) date, amount
from [order] o
where o.CustomerId=c.CustomerId
order by Id desc
)o

SQL sum of order value from joining two tables

I want to get the sum of sales of every order, along with customer and employee details from another table
Order Details table
OrderID ProductID UnitPrice Quantity Discount
10248 11 10 1 0
10248 42 20 2 0
10248 72 20 3 0
10249 14 10 1 0
10249 51 40 2 0
Orders table
OrderID CustomerName EmployeeName
10248 C1 E1
10249 C2 E2
Desired result
orderid sales Customer Employee
10248 110 C1 E1
10249 90 C2 E2
So I need total sum of sales for each order (e.g. 10248 order has sales 10*1 + 20*2 + 20*3 = 10+40+60=110) and corresponding employee name and customer name
Query tried
select od.orderid, Unitprice * Quantity as sales
group by od.orderid
From [Order Details] od
inner join orders o on od.orderid = o.orderid
Error:
Incorrect syntax near the keyword 'From'.
You need to aggregate by order, and then take the sum of the sales per order:
SELECT
od.orderid,
SUM(Unitprice * Quantity) AS sales
FROM [Order Details] od
INNER JOIN orders o
ON od.orderid = o.orderid
GROUP BY
od.orderid;
Try the following, you are having a group by before from. Also you do not need to do group by if you are using no aggregation instead you can use distinct.
select
od.orderid,
sum(Unitprice * Quantity) as sales
From [Order Details] od
inner join orders o on od.orderid=o.orderid
group by
od.orderid
FROM belongs before GROUP BY.
select od.orderid, unitprice * quantity as sales
from [Order Details] od
group by od.orderid;
With the order information joined:
select o.orderid, od.sales, o.customername, o.employeename
from orders o
join
(
select orderid, unitprice * quantity as sales
from [Order Details]
group by orderid
) od on od.orderid = o.orderid
order by o.orderid;
Use SUM() in conjuction with GROUP BY. I am incapable of testing but code like this should work on most SQL versions.
SELECT
od.orderid,
SUM(od.Unitprice * od.Quantity) as sales,
ot.CustomerName,
ot.EmployeeName
FROM od
INNER JOIN ot ON od.orderid=ot.orderid;
GROUP BY od.orderid;
You should be able to adapt the script to your database.

Sum between 3 linked tables SQL Server

I am trying to pull a sum from linked table.
Order:
OrderID LocationID OrderDate
100 1 1/1/2000
200 2 1/2/2000
OrderedItems:
ID OrderID ItemID
1 100 1
2 200 2
3 200 2
4 100 3
OrderItem:
ItemID ItemName Cost
1 Mobile1 100.00
2 Mobile2 200.00
3 Mobile3 300.00
The Order table is effectively a group of OrderedItems. Each row in OrderedItems links back to OrderItem via the ItemID.
I am trying to add a column to the below query for order total.
Order Number Location Date Ordered Order Total
-------------------------------------------------------
100 Sydney 1/1/2000 400
200 Brisbane 1/2/2000 400
The current query I have is:
SELECT
Order.OrderID AS [Order Number],
OL.Name AS [Location],
Order.OrderDate AS [Date Ordered]
FROM
Order
LEFT JOIN
Office_Locations AS OL ON OL.id = Order.LocationID
I have tried to follow this link however I am needing to link through 3 tables for the values to add.
Any hep would be great!
You're not finding a sum from three tables. You're finding a sum from one table: the OrderItem table. The only trick is getting the JOIN and GROUP BY expressions done correctly to make that column available.
SELECT o.OrderID As [Order Number], l.Name As Location
, o.OrderDate As [Date Ordered], SUM(i.Cost) As [Order Total]
FROM [Order] o
INNER JOIN Office_Locations l on l.id = o.LocationID
INNER JOIN OrderedItems oi on oi.OrderID = o.OrderID
INNER JOIN OrderItem i ON i.ItemID = oi.ItemID
GROUP BY o.OrderID, l.Name, o.OrderDate
SQLFIDDLE
You need to use SUM to get the total Cost:
SQL Fiddle
SELECT
[Order Number] = o.OrderID,
Location = ol.Name,
[Date Ordered] = o.OrderDate,
[Order Total] = SUM(i.Cost)
FROM [Order] o
INNER JOIN OrderedItems oi
ON oi.OrderId = o.OrderId
INNER JOIN OrderItem i
ON i.ItemID = oi.ItemID
LEFT JOIN Office_Locations ol
ON ol.id = o.LocationID
GROUP BY
o.OrderID, o.OrderDate, ol.Name
As commented by Joel Coehoorn, it's more normal to have a quantity field in the OrderedItems table than to repeat them. Following his advise, your OrderedItems table should be:
ID OrderID ItemID Quantity
1 100 1 1
2 200 2 2
3 100 3 1
Additional Notes:
Use meaningful aliases to improve readability.
Refrain from using reserved words as your object names i.e. Order could be renamed as OrderHeader.

Having trouble finding the right join statement for my query

I am trying to export data from a database and am joining the "customers" table with the "orders" table. It's a one to many relationship where customers can have multiple orders. I'm trying to write a query that returns basic customer info from the customers table - email_address, firstname, lastname, but to also include the date of the last order they placed.
customers as c
- customer_id
- firstname
- lastname
- email_address
orders as o
- orders_id
- customers_id
- purchase_date
I want the result to return a single result for each customer where the purchase date is the last purchase that customer made.
c.firstname, c.lastname, c.email_address, o.purchase_date
What is the correct SQL syntax to make this happen?
select c.*, o.LastOrderDate
from customers c
LEFT JOIN
(select customers_id, max(purchase_date) as LastOrderDate
from orders
group by customers_id) o on o.customers_id=c.customers_id
Will get all customers and the date of the last order, if one exists.
What about:
SELECT c.firstname, c.lastname, c.email_address, MAX(o.purchase_date)
FROM customers AS c
JOIN orders AS o ON o.customers_id = c.customer_id
GROUP BY c.firstname, c.lastname, c.email_address
This only lists customers who have placed at least one order. If you want all customers, then you should be able to use a LEFT JOIN instead of a simple (INNER) JOIN as shown.
This returns all Customers, regardless of whether they have any Orders:
SQL> select c.name
2 , c.email_address
3 , ( select max (o.order_date) from orders o
4 where o.customer_no = c.customer_no )as last_order
5 from customers c
6 /
NAME EMAIL_ADDRESS LAST_ORDE
-------------------- ------------------------- ---------
ACME Industries info#acme.com 07-APR-10
Tyrell Corporation accounts#tyrellcorp.com 26-MAR-10
Lorax Textiles Co the.lorax#hotmail.com
SQL>
It is equivalent to the LEFT OUTER JOIN:
SQL> select c.name
2 , c.email_address
3 , o.last_order_date
4 from customers c
5 left join ( select o.customer_no
6 , max (o.order_date) as last_order_date
7 from orders o
8 group by o.customer_no ) o
9 on o.customer_no = c.customer_no
10 /
NAME EMAIL_ADDRESS LAST_ORDE
-------------------- ------------------------- ---------
ACME Industries info#acme.com 07-APR-10
Tyrell Corporation accounts#tyrellcorp.com 26-MAR-10
Lorax Textiles Co the.lorax#hotmail.com
SQL>
A RIGHT OUTER JOIN would only return rows for Customers with Orders. Assuming an Order must have a Customer (i.e. enforced foreign key) then that would be the same as an INNER JOIN.
If your flavour of database supports analytic functions then RANK() offers an alternative way of solving it...
SQL> select name
2 , email_address
3 , order_date
4 from (
5 select c.name
6 , c.email_address
7 , o.order_date
8 , rank () over (partition by c.customer_no
9 order by o.order_date desc ) as rnk
10 from customers c
11 join orders o
12 on ( o.customer_no = c.customer_no)
13 )
14 where rnk = 1
15 /
NAME EMAIL_ADDRESS ORDER_DAT
-------------------- ------------------------- ---------
ACME Industries info#acme.com 07-APR-10
Tyrell Corporation accounts#tyrellcorp.com 26-MAR-10
SQL>
This also only returns rows for Customers with Orders.