SQL Query to Return Total Number of Lines and Number of Items - sql

I am running a query on two tables that needs to return the total number of lines in each sales order and a total of the items ordered.
A simplified version of the SalesOrder table is constructed like this:
SalesOrderID
Customer
SODate
102
Bob Smith
12/15/2021
101
Jane Doe
12/05/2021
100
Sarah Joy
12/01/2021
The second table, SalesOrderLine, contains the line items in the sales order:
SalesOrderID
LineNumber
Item
Quantity
100
1
Nuts
5
100
2
Bolts
10
100
3
Washers
3
101
1
Screws
15
102
1
Nails
25
102
2
Hooks
5
The result of the query would look like this:
SalesOrderID
SODate
Customer
TotalLines
TotalItems
102
12/15/2021
Bob Smith
2
30
101
12/05/2021
Jane Doe
1
15
100
12/01/2021
Sarah Joy
3
18
I am locking up on how to use the query to return the Total Number of Lines and Total Number of Items per SalesOrderID.
SELECT SalesOrder.SalesOrderID, SalesOrder.SODate, SalesOrder.SOCustomer
?? Total Number of Lines and Total Number of Items ??
FROM SalesOrder
INNER JOIN SalesOrders ON SalesOrder.SalesOrderID = SalesOrderLine.SalesOrderID
ORDER BY SalesOrderID

You can use apply :
select so.*, soo.*
from salesorder so cross apply
( select count(*) as Totallines, sum(soo.quantity) as TotalQty
from SalesOrders soo
where soo.SalesOrderID = so.SalesOrderID
) soo;

You are almost done, except the aggregation.
Query
select so.SalesOrderID, so.SODate, so.SOCustomer,
count(sol.LineNumber) as TotalLines, sum(sol.Quantity) as TotalItems
from SalesOrder as so
join SalesOrderLine as sol
on so.SalesOrderID = sol.SalesOrderID
group by so.SalesOrderID, so.SODate, so.SOCustomer
order by SalesOrderID;

Related

Access sql Moving Average of Top N With 2 criterias

I have been searching the forum and found a single post that is a little smilair to my problem here: Calculate average for Top n combined with SQL Group By.
My situation is:
I have a table tblWEIGHT that contains: ID, Date, idPONR, Weight
I have a second table tblSALES that contains: ID, Date, Sales, idPONR
I have a third table tblPONR that contains: ID, PONR, idProduct
And a fouth table tblPRODUCT that contais: ID, Product
The linking:
tblWEIGHT.idPONR = tblPONR.ID
tblSALES.idPONR = tblPONR.ID
tblPONR.idProduct = tblPRODUCT.ID
The maintable of my query is tblSALES. I want to all my sales listed, with the moving average of the top5
weights of the PRODUCT where the date of the weight is less than the sales date, and the product is the same as the sold product. Its IMPORTANT that the result isn't grouped by the date. I need all the records of tblSALES.
i have gotten as far as to get the top 1 weight, but im not able to get the moving average instread.
The query that gest the top 1 is the following, and i am guessing that the query i need is going to look a lot like it.
SELECT tblSALES.ID, tblSALES.Dato, tblPONR.idPRODUCT,
(
SELECT top 1 Weight FROM tblWEIGHT INNER JOIN tblPONR ON tblWeight.idPONR = tblPONR.ID
WHERE tblPONR.idPRODUCT = idPRODUCT AND
SALES.Date > tblWEIGHT.Date
ORDER BY tblWEIGHT.Date desc
) AS LatestWeight
FROM tblSALES INNER JOIN VtblPONR ON tblSALES.idPONR = tblPONR.ID
this is not my exact query since im danish and i wouldnt make sense. I know im not supposed to use Date as a fieldname.
i imagine the filan query would be something like:
SELECT tblSALES.ID..... avg(SELECT TOP 5 weight .........)
but doing this i keep getting error at max 1 record can be returned by this subquery
Final Question.
How do i make a query that creates a moving average of the top 5 weights of my sold product, where the date of the weight is earlier than the date i sold the product?
EDIT Sampledata:
DATEFORMAT: dd/mm/yyyy
tblWEIGHT
ID Date idPONR Weight
1 01-01-2020 1 100
2 02-01-2020 2 200
3 03-01-2020 3 200
4 04-01-2020 3 400
5 05-01-2020 2 250
6 06-01-2020 1 150
7 07-01-2020 2 200
tblSALES
ID Date Sales(amt) idPONR
1 05-01-2020 30 1
2 06-01-2020 15 2
3 10-01-2020 20 3
tblPONR
ID PONR(production Number) idProduct
1 2521 1
2 1548 1
3 5484 2
tblPRODUCT
ID Product
1 Bricks
2 Tiles
Desired outcome read comments for AvgWeight
tblSALES.ID tblSALES.Date tblSales.Sales(amt) AvgWeigt
1 05-01-2020 30 123 -->avg(top 5 newest weight of both idPONR 1 And 2 because they are the same product, and where tblWeight.Date<05-01-2020)
2 06-01-2020 15 123 -->avg(top 5 newest weight of both idPONR 1 And 2 because they are the same product, and where tblWeight.Date<06-01-2020)
3 10-01-2020 20 123 -->avg(top 5 newest weight of idPONR 3 since thats the only idPONR with that product, and where tblWeight.Date<10-01-2020)
Consider:
Query1
SELECT tblWeight.ID AS WeightID, tblWeight.Date AS WtDate,
tblWeight.idPONR, tblPONR.PONR, tblPONR.idProduct, tblWeight.Weight, tblSales.SalesAmt,
tblSales.ID AS SalesID, tblSales.Date AS SalesDate
FROM (tblPONR INNER JOIN tblWeight ON tblPONR.ID = tblWeight.idPONR)
INNER JOIN tblSales ON tblPONR.ID = tblSales.idPONR;
Query2
SELECT * FROM Query1 WHERE WeightID IN (
SELECT TOP 5 WeightID FROM Query1 AS Dupe WHERE Dupe.idProduct = Query1.idProduct
AND Dupe.WtDate<Query1.SalesDate ORDER BY Dupe.WtDate);
Query3
SELECT Query2.SalesID, Query2.SalesDate, Query2.SalesAmt,
First(DAvg("Weight","Query2","idProduct=" & [idProduct] & " AND WtDate<#" & [SalesDate] & "#")) AS AvgWt
FROM Query2
GROUP BY Query2.SalesID, Query2.SalesDate, Query2.SalesAmt;

How to get all products from one order to the list

I have written a query that returns data, here is my code
SELECT o.Id, p.ProductName, po.Quantity, p.Price, DeliveryMethod,
OrderDate, TotalSum, u.UserName FROM [Order] o
JOIN ProductsOrders po ON o.Id = po.OrderId
JOIN Product p ON po.ProductId = p.Id
JOIN Users u ON o.UserId = u.Id
ORDER BY o.Id
And it returns next:
OrderId ProductName Quantity Price DeliveryMethod OrderDate TotalSum UserName
98 Bed3 1 3000 Express 2018-08-04 7015 Ivan
98 Bed4 1 4000 Express 2018-08-04 7015 Ivan
100 Bed2 1 2000 2018-08-05 2000 Ivan
101 Bed2 1 2000 2018-08-05 5000 Ivan
101 Bed3 1 3000 2018-08-05 5000 Ivan
102 Bed0 1 0 Standard 2018-09-04 1005 Ivan
We can notice that for each product - one record
But I want to group all products by one order and get something like that:
- orderId
- deliveryMethod
- userName
- product1 quantity price
- ...
- productN quantity price
- totalAmount
101
Courier
John Doe
Black bag 1 1500
Fat Bike 1 5000
Thermos bottle 5 200
Total amount 7500
How can I modify the query?
The proper way to do this, IMO, would be to select 2 datasets. First dataset containing the parent Order data, and the second containing the individual ProductsOrders (product line items) for the Orders in the first dataset.
-- Select Orders
SELECT
[o].[Id] AS [OrderId]
,[o].[DeliveryMethod]
,[o].[OrderDate]
,[u].[UserName]
FROM [Order] [o]
INNER JOIN [Users] [u] ON [o].[UserId] = [u].[Id]
WHERE
[o].[Id] IN(SomeRangeOfOrderIds) -- (Or however you'd like to filter the results)
-- Select Products (product line items)
SELECT
[p].[ProductName]
,[po].[Quantity]
,[p].[Price]
FROM [ProductsOrders] [po]
INNER JOIN [Product] [p] ON [po].[ProductId] = [p].[Id]
WHERE
[po].[OrderId] IN(SameRangeOfOrderIdsAsTheQueryAbove)
...then take those results and display them however you'd like. Will this be appearing in a report? Or on a web page?
I have just implemented this issue in LINQ. Should have noticed that there is many-to-many relationship
var orders = db.Orders.Select(o => new
{
o.Id,
o.DeliveryMethod,
o.OrderDate,
o.UserId,
o.TotalSum,
Products = o.ProductsOrders.Select(p => new { p.Product.ProductName, p.Quantity, p.Product.Price}).ToList()
}).ToList();

Concatenating data from one row into the results from another

I have a SQL Server database of orders I'm struggling with. For a normal order a single table provides the following results:
Orders:
ID Customer Shipdate Order ID
-----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
At some point they needed orders that were placed by more than one customer. So they created a row for each customer and split the record over multiple rows.
Orders:
ID Customer Shipdate Order ID
-----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
3 John
4 Dan
5 2014-05-10 300
So there is another table I can join on to make sense of this which relates the three rows which are actually one order.
Joint.Orders:
ID Related ID
-----------------------------------------------------------------
5 3
5 4
I'm a little new to SQL and while I can join on the other table and filter to only get the data relating to Order ID 300, but what I'd really like is to concatenate the customers, but after searching for a while I can't see how to do this. What'd I'd really like to achieve is this as an output:
ID Customer Shipdate Order ID
----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
5 John, Dan 2014-05-10 300
You should consider changing the schema first. The below query might help you get a feel of how it can be done with your current design.
Select * From Orders Where IsNull(Customer, '') <> ''
Union All
Select ID,
Customer = (Select Customer + ',' From Orders OI Where OI.ID (Select RelatedID from JointOrders JO Where JO.ID = O.ID)
,ShipDate, OrderID
From Orders O Where IsNull(O.Customer, '') = ''

Full Join and sum 2 queries in access

I am very new to this type of complicated joins and summing functions.
I had 2 table queries which have same fields (i.e: ProdID, ProdName, NetQty, Unit)
The 1st one query contains OpStock and the 2nd one contains Purchase.
I want to add this 2 table query to make a single table so that I can able to see current stock.
The data looks like this for 1 st table is:
ProdID ProdName Qty
100 Rose 700
101 Lilly 550
103 Jasmine 600
105 Lavender 400
The data looks like this for 2nd table is:
ProdID ProdName Qty
100 Rose 400
101 Lilly 250
104 Lotus 1000
106 MariGold 400
The final data looks like this for 3rd table is:
ProdID ProdName Qty
100 Rose 1100
101 Lilly 800
103 Jasmine 600
104 Lotus 1000
105 Lavender 400
106 MariGold 400
How can i achieve this one using sql for access2003.
Thanks.
I am very sorry Ciaran,
This is purely access used for vb.net
Here Is my access query1
SELECT sp_OpenIandP_Prod.ProdID,
sp_OpenIandP_Prod.ProdName,
Sum(([sp_OpenIandP_Prod.SumOfNetQty]-[sp_OpenSales_Prod.SumOfNetQty])) AS NetQty,
sp_OpenIandP_Prod.UnitSName
FROM sp_OpenIandP_Prod
INNER JOIN sp_OpenSales_Prod ON sp_OpenIandP_Prod.ProdID=sp_OpenSales_Prod.ProdID
GROUP BY sp_OpenIandP_Prod.ProdID,
sp_OpenIandP_Prod.ProdName,
sp_OpenIandP_Prod.UnitSName;
The 1st query result would be like this:
ProdID ProdName NetQty UnitSName
1 Rose 0 Kgs
2 Lilly 7125 Mts
3 Lotus 12374 Nos
The second query is:
SELECT Products.ProdID, Products.ProdName,
Sum(OPDDetails.NetQty) AS SumOfNetQty, Units.UnitSName
FROM Units
INNER JOIN (Products
INNER JOIN (Brands
INNER JOIN OPDDetails ON Brands.BrID=OPDDetails.BrandID)
ON Products.ProdID=Brands.ProdID)
ON Units.UnitID=Products.UnitID
WHERE (((OPDDetails.PurID)>0)
AND ((OPDDetails.OPDDate)>=[StartDate] And (OPDDetails.OPDDate)<=[EndDate]))
GROUP BY Products.ProdID, Products.ProdName, Units.UnitSName;
and the result set would be like this:
ProdID ProdName SumOfNetQty UnitSName
1 Rose 1800 Kgs
2 Lilly 21000 Mts
I got the above result easily.
But it is not as much easy to get like this:
ProdID ProdName SumOfNetQty UnitSName
1 Rose 1800 Kgs
2 Lilly 28125 Mts
3 Lotus 12374 Nos
That's all. Thanks again.
This is not a vb.net question, however you need to use a UNION
Select ProdId, ProdName, Sum(Qty) As QtySum
From (Select ProdId, ProdName, Qty From TableA
Union All
Select ProdId, ProdName, Qty From TableB) DerrivedView
Group By ProdId, ProdName
You can create a UNION between your 2 queries then group by product:
SELECT ProdID, ProdName, Sum(NetQty) As NetQty, UnitSName
FROM
(
SELECT sp_OpenIandP_Prod.ProdID,
sp_OpenIandP_Prod.ProdName,
Sum(([sp_OpenIandP_Prod.SumOfNetQty]-[sp_OpenSales_Prod.SumOfNetQty])) AS NetQty,
sp_OpenIandP_Prod.UnitSName
FROM sp_OpenIandP_Prod
INNER JOIN sp_OpenSales_Prod ON sp_OpenIandP_Prod.ProdID=sp_OpenSales_Prod.ProdID
GROUP BY sp_OpenIandP_Prod.ProdID,
sp_OpenIandP_Prod.ProdName,
sp_OpenIandP_Prod.UnitSName
UNION ALL
SELECT Products.ProdID, Products.ProdName,
Sum(OPDDetails.NetQty) AS NetQty, Units.UnitSName
FROM Units
INNER JOIN (Products
INNER JOIN (Brands
INNER JOIN OPDDetails ON Brands.BrID=OPDDetails.BrandID)
ON Products.ProdID=Brands.ProdID)
ON Units.UnitID=Products.UnitID
WHERE (((OPDDetails.PurID)>0)
AND ((OPDDetails.OPDDate)>=[StartDate] And (OPDDetails.OPDDate)<=[EndDate]))
GROUP BY Products.ProdID, Products.ProdName, Units.UnitSName
)
GROUP BY ProdID, ProdName, UnitSName

SQL summary by ID with period to period comparison

I am a beginner in SQL, hope someone can help me on this:
I have a Items Category Table:
ItemID | ItemName | ItemCategory | Active/Inactive
100 Carrot Veg Yes
101 Apple Fruit Yes
102 Beef Meat No
103 Pineapple Fruit Yes
And I have a sales table:
Date | ItemID | Sales
01/01/2010 100 50
05/01/2010 101 200
06/01/2010 101 250
06/01/2010 102 300
07/01/2010 103 50
08/01/2010 100 100
10/01/2010 102 250
How Can I achieve a sales summary table by Item By Period as below (with only active item)
ItemID | ItemName | ItemCategory | (01/01/2010 – 07/01/2010) | (08/01/2010 – 14/01/1020)
100 Carrot Veg 50 100
101 Apple Fruit 450 0
103 Pineapple Fruit 0 0
A very dirty solution
SELECT s.ItemId,
(SELECT ItemName FROM Items WHERE ItemId = s.ItemId) ItemName,
ISNULL((SELECT Sum(Sales)FROM sales
WHERE [Date] BETWEEN '2010/01/01' AND '2010/01/07'
AND itemid = s.itemid
GROUP BY ItemId),0) as firstdaterange,
ISNULL((SELECT Sum(Sales)FROM sales
WHERE [Date] BETWEEN '2010/01/08' AND '2010/01/14'
AND itemid = s.itemid
GROUP BY ItemId), 0) seconddaterange
FROM Sales s
INNER JOIN Items i ON s.ItemId = i.ItemId
WHERE i.IsActive = 'Yes'
GROUP BY s.ItemId
Again a dirty solution, also the dates are hardcoded. You can probably turn this into a stored procedure taking in the dates as parameters.
I'm not too clued up on PIVOT command but maybe that will be worth a google.
You can pivot the data using the SQL PIVOT operator. Unfortunately, that operator has limited scope due to the requirement to pre-specify the output columns.
You normally achieve this by grouping on a calculated column (in this case, one that computes the week number or first day of the week in which each row falls). You can then either generate SQL on-the-fly with columns derived using SELECT DISTINCT week FROM result, or just drop the result into Excel and use its pivot table facility.