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
Related
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
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.
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.
I use this query to maintain my stock but its not show exact result
select p.Product_Name Product
,isnull(sum(d.qty),0) Purchase_Qty
,isnull(sum(i.qty),0) Issue_Qty
,(isnull(sum(d.qty),0)-isnull(sum(i.qty),0)) InStock
from purchase_dtl d
left join issue_dpt i on i.Product_ID=d.Product_ID
right join product p on p.id = d.Product_ID
group by Product_Name
Query result
Product | Purchase_Qty | Issue_Qty | InStock
---------------------------------------------
Pen 1000 300 700
Books 4000 1000 3000
My exact purchase qty
Product | Purchase_Qty
----------------------
Pen 500
Books 2000
My exact issue qty
Product | Issue_Qty
-------------------
Pen 300
Books 1000
Please help me to solve my problem
Thanks
select p.Product_Name Product
, p.Purchase_Qty
, isnull(sum(i.qty),0) Issue_Qty
, p.Purchase_Qty-isnull(sum(i.qty),0) InStock
from (select p.id, p.Product_Name, isnull(sum(d.qty),0) Purchase_Qty
from product p left join purchase_dtl d on p.id = d.Product_ID
group by p.id, p.Product_Name) p
left join issue_dpt i on i.Product_ID = p.id
group by Product_Name, p.Purchase_Qty
I suppose joining purchase_dtl and issue_dpt gives you some extra rows for Purchase_Qty
Join product with purchase_dtl first to calculate the aggregate data and then join again with issue_dpt
I have a table filled with purchase prices, like this:
sku price btw startdate
PCR-CA5425023181515 21,17 € 1 01/01/2009
PCR-CA5425023181515 999,00 € 1 06/06/2009
PCR-CA5425023181515 444,00 € 4 09/07/2009
PCR-CA5425023181515 100,00 € 4 10/08/2009
I have another table filled with orders, like this:
sku quantity orderdate
PCR-CA5425023181515 5 01/05/2009
PCR-CA5425023181515 10 01/12/2009
PCR-CA5425023181515 10 24/12/2009
My goal is to get every purchase price per order from that date.
(For example: when I ordered the product on the first of may (01/05) it cost 21,17 euros.
When I ordered it on the first of december (01/12) it cost 100,00 euros.)
I've been struggling with this for the past hour, but haven't found anything useful yet.
SELECT
O.sku,
O.qty,
PP.price
FROM
Orders O
INNER JOIN Purchase_Prices PP ON
PP.sku = O.sku AND
PP.start_date <= O.order_date
WHERE
NOT EXISTS
(
SELECT
*
FROM
Purchase_Prices PP2
WHERE
PP2.sku = PP.sku AND
PP2.start_date <= O.order_date AND
PP2.start_date > PP.start_date
)
Alternatively:
SELECT
O.sku,
O.qty,
PP.price
FROM
Orders O
INNER JOIN Purchase_Prices PP ON
PP.sku = O.sku AND
PP.start_date <= O.order_date
LEFT OUTER JOIN Purchase_Prices PP2 ON
PP2.sku = O.sku AND
PP2.start_date <= O.order_date AND
PP2.start_date > PP.start_date
WHERE
PP2.sku IS NULL