Access join of two subqueries - sql

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.

Related

Postgres distinct inner join (one to many) with n constraints on joined table

I'm trying to find the most efficient way to perform a Postgres query.
I have 2 tables
Orders (id, order_name)
Items (id, order_id, item_name)
Each order in the orders table has between 1 and n items listed in the items table.
What I want is to perform a query that returns all order that contains item Burger, item Pizza and item Coke.
Is the call below the best way to do such query?
SELECT DISTINCT ON (orders.id)
orders.id
FROM orders
INNER JOIN items i1 on orders.id = i1.order_id
INNER JOIN items i2 on orders.id = i2.order_id
INNER JOIN items i3 on orders.id = i3.order_id
WHERE i1.item_name = 'Burger'
AND i2.item_name = 'Fries'
AND i3.item_name = 'Coke'
Your approach works, and should be relatively efficient. Assuming that there are no duplicate order id / item names, you can remove distinct from the other query, which avoids unecessary work.
You could also use aggregation. It involves less additional typing when the number of items increases:
select o.*
from orders o
inner join items i on i.order_id = o.id
where i.item_name in ('Burger', 'Fries', 'Coke') -- any of the three items
group by o.order_id
having count(*) = 3 -- all items match
Again, this assumes no duplicates in items; else, you need having count(distinct i.item_name) = 3 instead.

Retrive total quantity of ordered Items using 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
)

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.

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

Selecting maximum value and inserting 0 if there are no entries

I have two tables, items and bids.
create table items (
id serial primary key,
store_id int,
min_bid int
);
create table bids (
item_id int,
amount int
);
I want to select items and include information about the max bid.
select items.*, max(bids.amount) from items
join bids on bids.item_id = items.id
where items.store_id = $store_id
group by items.id
However, when there are no bids for a particular item, the item just doesn't get selected. How can I make it so that when there are no bids, the item still gets selected and fills in the max(bids.amount) column with items.min_bid? (Or 0 is fine, too.)
I tried this:
select items.*, coalesce(max(bids.amount), items.min_bid) from items
join bids on bids.item_id = items.id
where items.store_id = $store_id
group by items.id
which doesn't work. I'm assuming it's because of the join that the items aren't getting selected in the first place.
What should I do?
The two crucial elements are LEFT JOIN and COALESCE().
#Adrian already commented on LEFT [OUTER ]JOIN. It preserves all rows at the left hand of the join and fills missing columns to the right with NULL values. The manual has more on the basics.
COALESCE() replaces NULL values with the provided alternative - 0 in this case.
SELECT i.*, COALESCE(max(b.amount), 0)
FROM items i
LEFT JOIN bids b ON b.item_id = i.id
WHERE i.store_id = $store_id
GROUP BY i.id
This alternative form is often faster when large parts of the sub-table are used: Aggregate in a subquery first, join later. This way you don't need an aggregation in the outer query. The second query also demonstrates how you can supply items.min_bid as replacement for NULL values.
SELECT i.*, COALESCE(b.max_amount, i.min_bid)
FROM items i
LEFT JOIN (
SELECT item_id, max(amount) AS max_amount
FROM bids
) b ON b.item_id = i.id
WHERE i.store_id = $store_id;
First, to display the items with no bids, you have to make use of a LEFT JOIN:
select items.*, max(bids.amount)
from items
left join bids on bids.item_id = items.id
where items.store_id = $store_id
group by items.id