Sum between 3 linked tables SQL Server - sql

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.

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.

Build customers report of last years with T-SQL

I've 3 tables (simplified):
-----------Orders--------------------
Id | Total_Price | Customer_Id | Date
--------Order Details---------------------
Id | Order_Id | Product Name | Qty | Value
----Customers------
Id | Name | Address
I take a total order value of single customer with this query:
SELECT C.ID, C.NAME , SUM(O.TOTAL_PRICE)
FROM CUSTOMERS C
JOIN ORDERS O ON O.CUSTOMER_ID = C.ID
GROUP BY C.ID, C.NAME
Now, I want to build a report with total order value filtered by a range of dates:
SELECT C.ID, C.NAME , SUM(O.TOTAL_PRICE)
FROM CUSTOMERS C
JOIN ORDERS O ON O.CUSTOMER_ID = C.ID
WHERE O.DATE BETWEEN #value1 AND #value2
GROUP BY C.ID, C.NAME
this works OK, but I want to select last 3 year sums of total orders value grouped by customer, this is the results that I want:
1Year | 2Year | 3Year | Customer_Name
-------------------------------------------------
XXX | YYY | ZZZZ | Customer1
XYX | YYZ | ZZTZ | Customer2
....
I've this cardinality:
Customer table with 22.000 rows
Orders table with 87.000 rows
Orders details with 600.000
It is possible without temptable,vartable or stored procedure with long execution time?
In my report I want also to calculate total Qty of last 3 years grouped by customer of a product, but this is the next step.
Any ideas?
Thanks
You can use a case statement to get the result you want. Since there is some ambiguity in your post about how the year ranges are defined, I've left out any calculations to get those year end/starts and just put variables in. You can revise to suit your need.
SELECT C.ID
,C.NAME
,SUM(CASE
WHEN o.DATE BETWEEN #year1start
AND #year1end
THEN O.TOTAL_PRICE
ELSE 0
END) Year1
,SUM(CASE
WHEN o.DATE BETWEEN #year2start
AND #year2end
THEN O.TOTAL_PRICE
ELSE 0
END) Year2
,SUM(CASE
WHEN o.DATE BETWEEN #year3start
AND #year3end
THEN O.TOTAL_PRICE
ELSE 0
END) Year3
FROM CUSTOMERS C
INNER JOIN ORDERS O ON O.CUSTOMER_ID = C.ID
GROUP BY C.ID
,C.NAME
Another option is to use pivot statement. I assume every your date range equals to one year (e.g. 2013, 2014 and so on).
If these years are strongly determined pivot isn't very beautiful option (look at full sqlfiddle example, it has possible solution for your additional question):
select
c.Id, c.Name, c.Address, CostByYear.[2013], CostByYear.[2014], CostByYear.[2015]
from Customers c
left join (
select
pt.Customer_Id, isnull(pt.[2013], 0) as [2013],
isnull(pt.[2014], 0) as [2014], isnull(pt.[2015], 0) as [2015]
from (
select
o.Customer_Id, year(o.Date) [Year], sum(o.Total_Price) [TotalCost]
from Orders o
group by
o.Customer_Id, year(o.Date)
) src
pivot (
sum(TotalCost) for [Year] in ([2013], [2014], [2015])
) pt
) CostByYear on
c.Id = CostByYear.Customer_Id
order by
c.Name
Also you can do both approaches (mine and prev answer) with dynamically created queries if year ranges aren't known and strongly defined.

SQL Sum of count across 3 tables

Say you have 3 tables:
Categories
Category ID
Name
Products
Product ID
Category ID (FK)
Sales
Product ID (FK)
Sale date
I'm trying to come up with a query that will result in a data table that shows the total number of sales per category, like:
Cat ID | Name | Total Sales
-------|------|-------------
1 | Red | 35
2 | Blue | 25
For bonus points, add a WHERE clause to select within a specific date range on the 'Sale Date' column.
I'm using SQL Server.
For SQL-Server could be something like that:
SELECT c.CategoryID AS [Cat ID],
c.Name AS [Name],
COUNT(s.ProductID) AS [Total Sales]
FROM Categories c
LEFT JOIN Products p
ON c.CategoryID = p.CategoryID
LEFT JOIN Sales s
ON p.ProductID = s.ProductID
WHERE s.Saledate BETWEEEN startDate and endDate
GROUP BY c.CategoryID, c.Name
select Categories.CatID, Categories.Name, count(*) as TotalSales
from Categories
join Products ON Categories.CategoryID = Products.CategoryID
join Sales ON Products.ProductID = Sales.ProductID
WHERE Sales.Saledate BETWEEEN date1 and date2
GROUP BY Categories.CatID, Categories.Name