Retrive total quantity of ordered Items using SQL - sql

I am trying to get Quantity of an item that is requested and yet not received.
Process of purchasing and Item is as
Created Purchase Order > Ordered Items saved in ItemsRequested table
Created Purchase Invoice > Received Items are in ReceivedItems table
Using below query to get Items Requested quantity but the result is wrong. What is logically wrong in query ?
select Sum(ItemRequested.Quantity) as OnOrder from ItemRequested
Inner join PurchaseOrders on ItemRequested.PurchaseOrderId = PurchaseOrders.PurchaseOrderId
Inner join PurchaseInvoices on PurchaseInvoices.PurchaseOrderId = PurchaseOrders.PurchaseOrderId
inner join ItemReceived on ItemReceived.PurchaseInvoiceId = PurchaseInvoices.PurchaseInvoiceId
where PurchaseOrders.DateOrdered >'2019-04-15 11:37:26.537' and ItemRequested.ItemId=3439

The definition of the items you need is "requested but not yet received". So you have to retrieve the rows that are in ItemRequested but absent from ItemReceived.
Thus your query should be more like this
SELECT SUM(ItemRequested.Quantity) AS OnOrder
FROM ItemRequested
INNER JOIN PurchaseOrders ON ItemRequested.PurchaseOrderId = PurchaseOrders.PurchaseOrderId
WHERE PurchaseOrders.DateOrdered >'2019-04-15 11:37:26.537'
AND ItemRequested.ItemId=3439
-- Exclude the PO having received items
AND NOT EXISTS (
SELECT 1
FROM PurchaseInvoices
INNER JOIN ItemReceived ON ItemReceived.PurchaseInvoiceId = PurchaseInvoices.PurchaseInvoiceId
WHERE PurchaseInvoices.PurchaseOrderId = PurchaseOrders.PurchaseOrderId
)

Related

Select most Occurred Value SQL with Inner Join

I am using this query to get the following data from different linked tables. But let's say the VENDORS for an item were three. Now here in result i want to show the Vendor which occurred most. I mean if Item ABC was supplied by 3 different vendors many times. Then here i want to get the Vendor who supplied most of the times item ABC.
My query is this.
use iBusinessFlex;
SELECT Items.Name,
Max(Items.ItemID) as ItemID ,
MAX(Items.Description)as Description,
MAX(ItemsStock.CurrentPrice) as UnitPrice,
MAX(ItemsStock.Quantity) as StockQuantiity,
MAX(Vendors.VendorName) as VendorName,
SUM(ItemReceived.Quantity) as TotalQuantity
From ItemReceived
INNER JOIN Items ON ItemReceived.ItemId=Items.ItemID
INNER JOIN ItemsStock ON ItemReceived.ItemId=ItemsStock.ItemID
INNER JOIN PurchaseInvoices ON PurchaseInvoices.PurchaseInvoiceId = ItemReceived.PurchaseInvoiceId
INNER JOIN Vendors ON Vendors.VendorId = PurchaseInvoices.VendorId
Group By Items.Name
EDIT : I have included this sub query but i am not sure if it is showing correct result. i mean Showing Vendor for each Item who provided that item most of the times
use iBusinessFlex;
SELECT Items.Name,
Max(Items.ItemID) as ItemID ,
MAX(Items.Description)as Description,MAX(ItemsStock.CurrentPrice) as UnitPrice,
MAX(ItemsStock.Quantity) as StockQuantiity,MAX(Vendors.VendorName) as VendorName,
SUM(ItemReceived.Quantity) as TotalQuantity
From ItemReceived
INNER JOIN Items ON ItemReceived.ItemId=Items.ItemID INNER JOIN ItemsStock
ON ItemReceived.ItemId=ItemsStock.ItemID INNER JOIN PurchaseInvoices
ON PurchaseInvoices.PurchaseInvoiceId = ItemReceived.PurchaseInvoiceId INNER JOIN Vendors
ON Vendors.VendorId IN (
SELECT Top 1 MAX(PurchaseInvoices.VendorId) as VendorOccur
FROM PurchaseInvoices INNER JOIN Vendors ON Vendors.VendorId=PurchaseInvoices.VendorId
GROUP BY PurchaseInvoices.VendorId
ORDER BY COUNT(*) DESC
And the Result Looks like this.
First, I would start with who ordered what thing the most. But the MOST is based on what... the most quantity? Price?, Number of Times? If you use one vendor and order 6 times qty of 10 you have 60 things. But order 1 time from another vendor for 100 qty, which one wins. You have to decide the basis of MOST, but I will go based on most times
per your original question.
So all things come from PurchasedInvoices which has a vendor ID. I dont care who the vendor is, just their ID, so no need to join. Also, don't need the item name if I am just looking for my counts. The query below will show per item, each vendor and their respective most times ordered and quantities ordered. I added the items and vendor table joins just to show the names.
select
IR.ItemID,
PI.VendorID,
max( I.Name ) Name,
max( V.VendorName ) VendorName,
count(*) as TimesOrderedFrom,
SUM( IR.Quantity ) as QuantityFromVendor
from
ItemsReceived IR
JOIN PurchaseInvoices PI
on IR.PurchaseInvoiceID = PI.PurchaseInvoiceID
JOIN Items I
on IR.ItemID = I.ItemID
JOIN Vendors V
on IR.VendorID = V.VendorID
group by
IR.ItemID,
PI.VendorID
order by
-- Per item
IR.ItemID,
-- Most count ordered
count(*),
-- If multiple vendors, same count, get total quantity
sum( IR.Quantity )
Now, to get only 1 per item, this would create a correlated subquery and you
can add 'TOP 1' to return only the first by this. Since the aggregate of count
is already done, you can then get the vendor contact info.
select
I.Name,
V.VendorName,
TopVendor.TimesOrderedFromVendor,
TopVendor.QuantityFromVendor
from
Items I
JOIN ( select TOP 1
IR.ItemID,
PI.VendorID,
count(*) as TimesOrderedFrom,
SUM( IR.Quantity ) as QuantityFromVendor
from
ItemsReceived IR
JOIN PurchaseInvoices PI
on IR.PurchaseInvoiceID = PI.PurchaseInvoiceID
where
-- correlated subquery based on the outer-most item
IR.ItemID = I.ItemID
group by
IR.ItemID,
PI.VendorID
order by
-- Per item
IR.ItemID,
-- Most count ordered
count(*),
-- If multiple vendors, same count, get total quantity
sum( IR.Quantity ) ) TopVendor
on I.ItemID = TopVendor.ItemID
JOIN Vendors V
on TopVendor.VendorID = V.VendorID
No sense in having the INNER Subquery joining on the vendor and items just for the names. Get those once and only at the end when the top vendor is selected.

Is there a way to condense rows further in a SQL query through grouping on more than one column?

Below you'll see a SQL query that successfully returns the revenue for a given merchant... unless any of that merchant's invoices happens to have more than one successful transaction. In that case, it will sum each invoice items revenue times its number of successful transactions.
If I wasn't already joining merchants and grouping by merchant.id, I would group by invoices.id
When you give GROUP BY multiple columns, it will only group together rows that are the same in both columns, resulting in a table that is less condensed rather than more condensed. Is there a way to run something along the lines of a second group by on this query such that it won't add the revenue any invoice's invoice items more than once?
SELECT merchants.id,
sum(invoice_items.unit_price * invoice_items.quantity) as total_revenue FROM merchants
INNER JOIN invoices
ON invoices.merchant_id = merchants.id
INNER JOIN invoice_items
ON invoice_items.invoice_id = invoices.id
INNER JOIN transactions
ON transactions.invoice_id = invoices.id
WHERE transactions.result = "success"
AND merchants.id = ?
GROUP BY merchants.id;
You have a N-to-M relationship that is causing invoices items to be sumed more than once. One solution would be to move the computation of the total per invoice to a subquery :
SELECT merchants.id, invoice_items_total.total_revenue
FROM merchants
INNER JOIN invoices
ON invoices.merchant_id = merchants.id
INNER JOIN
(
SELECT invoice.id, sum(unit_price * quantity) as total_revenue
FROM invoices_item
GROUP BY invoice.id
) invoice_items_total ON invoice_items_total.invoice_id = invoices.id
INNER JOIN transactions
ON transactions.invoice_id = invoices.id
WHERE transactions.result = "success"
AND merchants.id = ?
GROUP BY merchants.id;

Access SQL query inner join & sum with null

Tables: Items, Purchases, QuoteLines.
Items has fields ItemID, ItemName, IsActive
Purchases has fields ItemID, QtyPurchased
QuoteLines has fields ItemID, NegQty, IsSold
The goal is to select all ItemID's where IsActive=yes then sum all QtyPurchased and subtract only the NeqQty where IsSold=yes
I have tried:
SELECT Items.ItemID, Items.ItemName, IIF(NegQTY=NULL, SUM(QtyPurchased), SUM(NegQty+PurchasedQty)) AS Inv_Qty
FROM Purchases, Items, QuoteLines
WHERE Purchases.ItemID=Items.ItemID AND Items.ItemID=QuoteLines.ItemID
GROUP BY Items.ItemID, Items.ItemName;
This results in "your query does not include the specified expression IIF(NegQTY=NULL, SUM(QtyPurchased), SUM(NegQty+PurchasedQty))"
I also tried an inner join between tblItems and tblPurchases to get the PurchasedQty then a second inner join between tblItems and tblQuoteLines to get only the SoldQty, then a left inner join between the PurchasedQty and SoldQty to get InventoryQty, this however gave the right value for items that existed in both PurchasedQty and SoldQty, but for items that only existed in PurchasedQty it returned NULL.
Consider using saved queries to calculate the total units purchased and the total units sold, then use those saved queries in the query that calculates the current inventory.
Total Units Purchased
Create a saved query named [TotalPurchasedByItemID]
SELECT
Items.ItemID,
Sum(Purchases.QtyPurchased) AS SumOfQtyPurchased
FROM
Items
INNER JOIN
Purchases
ON Items.ItemID = Purchases.ItemID
WHERE (((Items.IsActive)=True))
GROUP BY Items.ItemID;
Total Units Sold
Create a saved query named [TotalSoldByItemID]
SELECT
Items.ItemID,
Sum(QuoteLines.NegQty) AS SumOfNegQty
FROM
Items
INNER JOIN
QuoteLines
ON Items.ItemID = QuoteLines.ItemID
WHERE (((Items.IsActive)=True) AND ((QuoteLines.IsSold)=True))
GROUP BY Items.ItemID;
Current Inventory
SELECT
Items.ItemID,
Items.ItemName,
Nz([SumOfQtyPurchased],0)-Nz([SumOfNegQty],0) AS Inv_Qty
FROM
(
Items
LEFT JOIN
TotalPurchasedByItemID
ON Items.ItemID = TotalPurchasedByItemID.ItemID
)
LEFT JOIN
TotalSoldByItemID
ON Items.ItemID = TotalSoldByItemID.ItemID
WHERE (((Items.IsActive)=True));

Join with count conditition

Consider the following Schema:
Table Invoices:
Id|TotalSum|Status
1|12|1
1|13|0
Table ClientInvoices:
Id|ClientId|InvoiceId
Table "invoices" may contain multiple invoices with the same Id but with different status (there is unique constraint on Id and status.). Status is integer that represents enum (0 - inactive, 1 - active)
I want to get all the client invoices with price changes if any:
ClientId|InvoiceId|SumBefore|SumAfter
If there is no inactive invoices then PreviousPrice should be null. I am trying to achieve this using the following query:
SELECT Clients.Id AS ClientId,
Invoice.Id AS InvoiceId,
ActualInvoice.TotalSum AS SumBefore,
InActiveInvoice.TotalSum AS SumAfter
FROM Invoices
LEFT JOIN ClientInvoices AS ActualInvoice ON ActualInvoice.InvoiceId AND Status = 1
LEFT JOIN ClientInvoices AS Inactive ON ActualInvoice.InvoiceId AND Status = 0
LEFT JOIN Clients ON Clients.Id = ClientInvoices.ClientId
This works well if there are two records for one invoice: past(inative) and current. However if there is only one invoice - it has active status and using the query above I get SumBefore = null and SumAfter = value which should be in SumBefore column.
It would be great if I could specify to join record on condition if count of row of that record is f.e. 1. Is that possible?
I think this should work:
select c.ClientId as ClientId,
a.InvoiceId as InvoiceId,
a.TotalSum as SumBefore,
b.TotalSum as SumAfter
from Invoices a left join Invoices b
on a.InvoiceId = b.InvoiceId
and a.status = 1 and b.status = 0
join ClientsInvoices c on c.InvoiceId = a.InvoiceId

Access join of two subqueries

I am constructing a simple database for an inventory system, with a barcode reader. I have one form to add inventory, and one form to remove inventory. Each adjust add a column to the add or remove table.
I made queries for my add and remove that return the total value of each item, associated with the id for each item. I want to join my add and remove tables so I can calculate the difference for a current quantity.
I am running into trouble with joining my add subquery and my remove subquery.
Add:
SELECT Items.description, Count(Trans_Add.s) AS Quantity
FROM Items INNER JOIN Trans_Add ON Items.ID = Trans_Add.s
GROUP BY Items.description;
Remove:
SELECT Items.description, Count(Trans_Remove.s) AS Quantity
FROM Items INNER JOIN Trans_Remove ON Items.ID = Trans_Remove.s
GROUP BY Items.description;
Whenever I try to assign alias for either in the from clause of my new query and join them it does not work.
Try:
SELECT Items.ID, Items.Description, (Items.TotalCount + A.Quantity - B.Quantity) as OnHandQty
FROM Items INNER JOIN
(SELECT Items.ID, Count(Trans_Add.s) AS Quantity
FROM Items INNER JOIN Trans_Add ON Items.ID = Trans_Add.s
GROUP BY Items.description
) A
ON Items.ID = A.ID
INNER JOIN (
SELECT Items.description, Count(Trans_Remove.s) AS Quantity
FROM Items INNER JOIN Trans_Remove ON Items.ID = Trans_Remove.s
GROUP BY Items.description
) B
ON Items.ID = B.ID
I made up a Field named TotalCount because you did not mentioned what is the Item Quantity in Items table. So, change it accordingly, that is, according to the
right field name for Item Quantity from Items table.