Access SQL query inner join & sum with null - sql

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));

Related

Get all records having count from one table is greater than sum of other table

I have three tables 1) CustomerOrders, 2) StockItems and 3) OrderContentsLine. StockItems have customerorderid (one to many relationship with CustomerOrders) and OrderContentsLine contains order items with item quantity (obviously one to many relationship with CustomerOrders).
Now I want to get All orders which have sum of quantity from OrderContentsLine table greater than count of StockItems
myquery looks like this
select co.OrderNumber,si.SalesOrderID, sum(ocl.Quantity) Ordered, count(si.SalesOrderID) Allocated from CustomerOrders co
inner join StockItems si on co.OrderID = si.SalesOrderID
inner join OrderContentsLine ocl on ocl.OrderID=co.OrderID
where co.CompanyId=531
group by si.SalesOrderID,co.OrderNumber
having count(si.SalesOrderID)>sum(ocl.Quantity)
but this query shows no results, and I am damn sure that many orders have greater order conterntline items than sum of quantity from StockItems table.
Can you please review my query and suggest the better way to get these orders!
My required output is
NOTE: this output is not generated by query !
I have just created a query that gives me the required output
select * from(
select co.OrderNumber, co.OrderID, co.OrderStatus,
(select sum(tbl.Quantity) from OrderContentsLine tbl where tbl.OrderID=co.OrderID) Ordered,
(select count(*) from StockItems tbl2 where tbl2.SalesOrderID=co.OrderID ) Allocated
from CustomerOrders co
)temp where temp.Allocated> temp.Ordered
Your problem is the multiple one-to-many joins. You are counting and summing duplicates. For example, if you have 1 order with 2 stock items, and 3 order lines, your join of the three tables will have 6 rows. You have no relationship between StockItem and OrderContentsLine, so you get a cartesian product.
You probably want something like
WITH ord AS
(
SELECT co.CompanyId, co.OrderID, co.OrderNumber, SUM(ocl.Quantity) AS Ordered
FROM CustomerOrders co
INNER JOIN OrderContentsLine ocl ON ocl.OrderID = co.OrderID
GROUP BY co.CompanyId, co.OrderNumber
), al AS
(
SELECT co.CompanyId, co.OrderID, co.OrderNumber, COUNT(si.SalesOrderID) AS Allocated
FROM CustomerOrders co
INNER JOIN StockItems si ON co.OrderID = si.SalesOrderID
GROUP BY co.CompanyId, co.OrderNumber
)
SELECT ord.CompanyId, ord.OrderNumber, ord.Ordered, al.Allocated
FROM ord
INNER JOIN al ON ord.OrderID = al.OrderID
WHERE companyId = 531
AND al.Allocated > ord.Ordered
Obviously hard to test with no data

subquery uses ungrouped column "psi.product_id" from outer query

I have the following model:
For every stock item, I'd like to know the the total ordered amount. In my model, every product is linked to one or many stock items together with an amount. And every order item is linked to a product, also with an amount.
Example: The product is "Screws Box", and it's linked to 50x stock item "Screw". A customer placed an order with 3x "Screws Box". That leads to a total of 150 ordered screws.
The query I built is the following:
SELECT
stock_item.id,
(
SELECT
SUM("amount"),
(
SELECT SUM("amount")
FROM order_item AS item
WHERE item.product_id = psi.product_id
) AS "item_amount"
FROM product_productstockitem AS psi
WHERE psi.stock_item_id = stock_item.id
) AS "product_amount"
FROM stock_stockitem AS stock_item
;
PostgreSQL tells me this:
ERROR: subquery uses ungrouped column "psi.product_id" from outer query
LINE 10: WHERE item.product_id = psi.product_id
How can this be achieved?
I think you want to join the tables together and aggregate:
select s.id,
sum(psi.amount * oi.amount)
from stock_stockitem s left join
product_productstockitem psi
on psi.stock_item_id = stock_item.id left join
order_item oi
on oi.product_id = psi.product_id
group by s.id

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 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.