I have the following tables
Location (Id, locationName)
Inventory (productid, qty, locationid)
With the following data, I need to query to show all locations per productid, even when not in inventory table. example of records below.
Table Location
Id Location Name
--------------------
1 Plant
2 Warehouse
3 Container
Table Inventory:
Productid Qty Locationid
-----------------------------
45 30 1
45 56 2
3 15 1
3 50 3
15 25 3
Desired result for my query:
Productid Qty LocationName
---------------------------------
45 30 Plant
45 56 Warehouse
45 0 Container
3 15 Plant
3 0 Warehouse
3 50 Container
15 0 Plant
15 0 Warehouse
15 25 Container
So far I have tried many different ways but no luck, so any help will be appreciated.
You can use the following query:
SELECT p.ProductId,
COALESCE(qty,0) AS qty,
[Location Name]
FROM LOCATION l
CROSS JOIN (SELECT DISTINCT ProductId FROM Inventory) AS p
LEFT JOIN Inventory i ON l.Id = i.locationid AND p.Productid = i.Productid
ORDER BY Productid, [Location Name]
The query uses CROSS JOIN to get all possible combinations between locations and products.
Demo here
Select y., isNull(z.Quantity,0) as Quantity
From
(
Select Location., x.ProductId
From Location,(Select Distinct ProductId From Inventory) as x
) as y
Left Outer Join Inventory z ON y.Id = z.LocationId
and y.ProductId = z.ProductId
Related
I'm trying to reduce storage with packages included in sold products.
Products can have different amounts of same packages and invoice can have different amounts of products in separate lines. Action should be performed against certain invoiceID.
Simplified tables (summary is not column, just added to ease up calculation):
Inv_rows
InvID ProdID Qty *Summary*
999 100 2 *100 = 10*
999 101 2 *101 = 2*
999 102 2 *102 = 2*
999 103 2 *103 = 10*
999 100 8
999 103 8
Pack_to_prod
ProdID PackID Qty
100 A 2 *A = 20*
100 B 1 *B = 10*
101 A 1 *A = 2*
101 B 1 *B = 2*
102 A 3 *A = 6*
103 B 2 *B = 20*
Storage
ItemID Qty
A 100 *A = 28*
B 100 *B = 32*
**Desired Result**
Storage
ItemID Qty
A 72 *(100-28)*
B 68 *(100-32)*
What I have tried is:
UPDATE Storage
SET Storage.Qty = Storage.Qty -
(SELECT SUM (Inv_rows.Qty * Pack_to_prod.Qty) FROM Inv_rows
WHERE Inv_rows.ProdID IN (SELECT ProdID FROM Pack_to_prod
WHERE Pack_to_prod.PackID=Storage.ItemID) AND Inv_rows.InvId = 999
)
FROM Inv_rows, Storage, Pack_to_prod
WHERE Inv_rows.ProdID = Pack_to_prod.ProdID
AND Pack_to_prod.PackID = Storage.ItemID
AND Inv_rows.InvID = 999
But the problem is the 'IN' since it doesn't match the rows but I can't use '=' as 'where' results more than one line.
Then I tried to simplify it for myself (as I'm not a professional) with a select clause to understand what exactly needs to be done..
SELECT
Pack_to_prod.PackID AS PackageID,
Inv_rows.ProdID AS ProductID,
Inv_rows.Qty AS ProductQty,
Pack_to_prod.Qty AS PackageQtyPerProduct,
Inv_rows.Qty*Pack_to_prod.Qty AS PackageTotal,
Storage.Qty AS StorageQty,
Storage.Qty - (Inv_rows.Qty * Pack_to_prod.Qty) AS NewStorageQty
FROM Pack_to_prod,Inv_rows,Storage
WHERE Inv_rows.ProdID = Pack_to_prod.ProdID
AND Pack_to_prod.PackID = Storage.ItemID
AND Inv_rows.InvID = 999
GROUP BY Inv_rows.ProdID, Pack_to_prod.PackID, Pack_to_prod.Qty, Storage.Qty, Inv_rows.Qty
Which results as simple list showing the problem why they can't be just summed up:
PackageID ProductID ProductQty PackageQtyPerProduct PackageTotal StorageQty NewStorageQty
A 100 2 2 4 100 96
A 100 8 2 16 100 84
B 100 2 1 2 100 98
B 100 8 1 8 100 92
A 101 2 1 2 100 98
B 101 2 1 2 100 98
A 102 2 3 6 100 94
B 103 2 2 4 100 96
B 103 8 2 16 100 84
But can't figure out how to make it run 'line by line' so that each 'Pack_to_prod.Qty' would be handled separately.
Any help in right direction appreciated.
This seems like some aggregations and joins. To get the changes in values, then:
select pp.packid, sum(p.qty * pp.qty) as new_qty
from (select ir.prodid, sum(qty) as qty
from inv_rows ir
group by ir.prodid
) p join
Pack_to_prod pp
on pp.prodid = p.prodid
group by pp.packid;
You can then use this in an update:
update s
set s.qty = s.qty - pp.new_qty
from storage s join
(select pp.packid, sum(p.qty * pp.qty) as new_qty
from (select ir.prodid, sum(qty) as qty
from inv_rows ir
group by ir.prodid
) p join
Pack_to_prod pp
on pp.prodid = p.prodid
group by pp.packid
) pp
on pp.packid = s.itemid;
This was explained very well. The SQL code is user older coding conventions (such as JOIN conditions in the WHERE clause, instead of FROM) and isn't organized into subqueries properly. All the pieces are present though. I think something like this is what you're looking for.
with
inv_cte(ProdID, sum_qty) as (
select ProdID, sum(Qty)
from Inv_rows
group by ProdID),
pack_cte(PackID, prod_qty) as (
select pp.PackID, sum(pp.Qty*ic.sum_qty)
from Pack_to_prod pp
join inv_cte ic on pp.ProdID=ic.ProdID
group by pp.PackID)
select s.ItemID, s.Qty-p.prod_qty as ResultQty
from Storage s
join pack_cte p on s.ItemID=p.PackID;
Update statement
with
inv_cte(ProdID, sum_qty) as (
select ProdID, sum(Qty)
from Inv_rows
group by ProdID),
pack_cte(PackID, prod_qty) as (
select pp.PackID, sum(pp.Qty*ic.sum_qty)
from Pack_to_prod pp
join inv_cte ic on pp.ProdID=ic.ProdID
group by pp.PackID)
update s
set Qty=Qty-p.prod_qty
from Storage s
join pack_cte p on s.ItemID=p.PackID;
I have the following query,
SELECT * FROM Products P
OUTER APPLY
(
SELECT COALESCE(CP.NewPrice, CP.Price, 2147483647) AS MinimumChildPrice
--,SelectedMinimumPriceRow.Promotion
FROM Products CP
WHERE CP.ParentID = P.ID
) AS C
The problem is SelectedMinimumPriceRow.Promotion. I need to select this extra Promotion column of selected Minimum Price/NewPrice?
For example if I have,
ID ParentID Promotion Price NewPrice
----------------------------------------
1 NULL a 81 52
2 1 b 11 81
3 1 c 91 14
4 1 d 11 25
5 1 e 10 61
For ID=1, the minimum price will be 14. So, I need to select c as well.
You could simply replace your OUTER APPLY query with a TOP 1 query ordering by price, that will allow you to grab any column;
SELECT * FROM Products P
OUTER APPLY
(
SELECT TOP 1 COALESCE(CP.NewPrice, CP.Price, 2147483647) MinimumChildPrice,
promotion MinimumChildPricePromotion
FROM Products CP
WHERE CP.ParentID = P.ID
ORDER BY COALESCE(CP.NewPrice, CP.Price, 2147483647)
) AS C
An SQLfiddle to test with.
I have an inner join, but I want it to select a default row if it does not find any match on the field [prices.Item], say a row in [Prices] with 'Unassigned' as the [Item] and a [Price] equal to 5. My code for the join is as follows:
SELECT
Orders.Item,
Orders.Quantity,
Prices.Price,
Orders.Quantity * Prices.Price AS Cost
FROM
Orders
INNER JOIN
Prices
ON Orders.Item = Prices.Item
In order to get the results you desire we need to combine the results from two queries: one for items with prices that actually exist in the [Prices] table, and another for the items that don't have a "real" price. This is done using a UNION query.
For [Orders]...
Item Quantity
------- --------
Edam 1
Gouda 2
Brie 3
Cheddar 4
Havarti 5
...and [Prices]...
Item Price
---------- -----
Edam 10
Gouda 11
Brie 12
Havarti 13
unassigned 5
...the query...
SELECT
Orders.Item,
Orders.Quantity,
Prices.Price
FROM
Orders
INNER JOIN
Prices
ON Orders.Item = Prices.Item
UNION ALL
SELECT
Orders.Item,
Orders.Quantity,
DLookup("Price","Prices","Item='unassigned'") AS Price
FROM
Orders
LEFT JOIN
Prices
ON Orders.Item = Prices.Item
WHERE Prices.Item IS NULL
...returns
Item Quantity Price
------- -------- -----
Edam 1 10
Gouda 2 11
Brie 3 12
Havarti 5 13
Cheddar 4 5
We can either save that query in Access (to use with other queries), or we can just put a "wrapper" around it to do the calculation
SELECT
Item,
Quantity,
Price,
Quantity * Price AS Cost
FROM
(
SELECT
Orders.Item,
Orders.Quantity,
Prices.Price
FROM
Orders
INNER JOIN
Prices
ON Orders.Item = Prices.Item
UNION ALL
SELECT
Orders.Item,
Orders.Quantity,
DLookup("Price","Prices","Item='unassigned'") AS Price
FROM
Orders
LEFT JOIN
Prices
ON Orders.Item = Prices.Item
WHERE Prices.Item IS NULL
)
...which gives us
Item Quantity Price Cost
------- -------- ----- ----
Edam 1 10 10
Gouda 2 11 22
Brie 3 12 36
Havarti 5 13 65
Cheddar 4 5 20
I have 2 tables
Products table:
ID ProductName Category
0 T-Shirt 15
1 Aqua De Gio 12
2 Jacket 15
3 Hot Water 13
Categories table:
categoryID catagoryName highercategoryID
8 Fragnance 0
99 Clothing 0
15 Armani Clothing 99
12 Armani Fragnance 8
102 Davidoff Fragnance 8
Expected result
ID ProductName Category CategoryTree
0 T-Shirt 15 Clothing > Armani Cloting
1 Aqua De Gio 12 Fragnance > Armani Fragnance
2 Jacket 15 Clothing > Armani Cloting
3 Hot Water 13 Fragnance > Davidoff Fragnance
For example take the T-Shirt from the products table
its category is 15.
go for the categories table and see where categoryID=15
look at the highercategoryID if its = 0 stop, if not then take its value 99
look for 99 in the categoryID column, the higher category now is 0 so stop.
based on the above I need to get "Clothing > Armani Clothing".
I am new to SQL queries and here is my first try
select
x.*,
x.p1 + isnull((' > ' + x.c1), '') + isnull((' > ' + x.c2), '') as CategoryTree
from
(select
RP.categoryid as catid,
RP.catagoryName as p1,
R1.catagoryName as c1,
R2.catagoryName as c2
from
categories as RP
left outer join
categories as R1 on R1.highercategoryid = RP.categoryid
left outer join
categories as R2 on R2.highercategoryid = R1.categoryid
left outer join
categories as R3 on R3.highercategoryid = R2.categoryid
where
RP.highercategoryid != 0 ) x
I am not sure how to stop the joining when I find the 0 value in the higher category, and how to join the products on their categories, and is there a dynamic way without using a lot of joins?
Here it goes:
With CTE (CatID, CatName, HigherCatID) AS
(
SELECT categoryID, CAST(catagoryName AS VARCHAR(1000)), highercategoryID
FROM CATEGORIES
UNION ALL
SELECT C.categoryID, CAST(CTE.CatName + ' > ' + C.catagoryName AS VARCHAR(1000)), CTE.HigherCatID
FROM CATEGORIES C
INNER JOIN CTE ON C.HigherCategoryID = CTE.CatID
)
SELECT P.ID, P.ProductName, Cte.CatID, CTE.CatName
FROM CTE INNER JOIN PRODUCTS P
ON (CatID = P.Category)
WHERE CTE.HigherCatID=0
you got a SQLFiddle Here
I have a table name 'Product'
ProductID ProductName
1 A
2 B
3 C
4 D
Another table named 'ViewedProduct'
ProductID Views UserID
2 2 55
2 1 40
1 10 40
1 50 127.0.1
3 51 127.0.1
for UserID 55 the expected result should be
ProductID ProductName
2 B
1 A
3 C
4 D
UserID 55 views should be at top and all other viewdproduct should come after it order by sum of their views. The product id 1 viewed by two different UserIDs thei total views is 60 that why it should come in second place. and product id 3 have 51 views it should come in third place.
Second Example :
ProductID Views UserID
2 2 55
3 3 55
2 1 40
1 10 40
1 50 127.0.1
3 51 127.0.1
4 50 127.0.1
Now for UserID 55 , it should first sort the result based on UserID 55. Then comes the rest result. Now the expected result i need should be
ProductID ProductName
3 C
2 B
1 A
4 D
Product ID 3 and 2 is not top because UserId 55 has viewed this 3 and 2 times respectively, the productid 1 is on the third place UserID 55 have not viewed this product. but their total views from viewed table is 60. And productID 4 comes last because userid 55 have not viewed this product but it total views from view table is 50. and so on..
-- Please comment if you need further explanation
I've edited the query to include the userID in the join clause as I believe this is necessary. see fiddle here: http://www.sqlfiddle.com/#!3/0ef18/1
SELECT
Product.ProductID,
Product.ProductName
FROM
Product
LEFT JOIN ViewedProduct ON Product.ProductID = ViewedProduct.ProductID AND ViewedProduct.UserID = #userID
WHERE
ViewedProduct.UserID IS NULL
OR ViewedProduct.UserID = #userID
ORDER BY
CASE WHEN ViewedProduct.Views IS NULL THEN 0 ELSE ViewedProduct.Views END DESC,
Product.ProductID
To order by the following:
UserViews,
AllViews,
ProductID
Use the following:
SELECT
Product.ProductID,
Product.ProductName
FROM
Product
LEFT JOIN ViewedProduct ON Product.ProductID = ViewedProduct.ProductID AND ViewedProduct.UserID = #userID
LEFT JOIN
(SELECT
ProductID,
SUM(Views) AllViews
FROM
ViewedProduct
GROUP BY
ProductID) TotalViewedProduct ON Product.ProductID = TotalViewedProduct.ProductID
ORDER BY
CASE WHEN ViewedProduct.Views IS NULL THEN 0 ELSE ViewedProduct.Views END DESC,
TotalViewedProduct.AllViews DESC,
Product.ProductID
It's not clear what you are asking here but if you want to return results from one of these tables and sort it by a column in another table just create a join between the main table and the table that holds the column you want to sort on. This will allow you to sort on columns in the joined table.
SELECT Product.ProductID, Product.ProductName
FROM Product
LEFT JOIN ViewedProduct ON Product.ProductID = ViewedProduct.ProductID
ORDER BY ViewedProduct.UserID
This however will not return the results you expect as UserID 55 has not viewed ProductID 1 or 3 and ordering will simply order ascending or descending.
If you want products viewed by UserID 55, you'll need a where clause:
SELECT Product.ProductID, Product.ProductName
FROM Product
LEFT JOIN ViewedProduct ON Product.ProductID = ViewedProduct.ProductID
WHERE ViewedProduct.UserID = 55
This will just return one row, unless there is more data than in your sample.
If you want to order by number of views try something like:
SELECT Product.ProductID, Product.ProductName
FROM Product
LEFT JOIN ViewedProduct ON Product.ProductID = ViewedProduct.ProductID
WHERE ViewedProduct.UserID = 55
ORDER BY ViewedProduct.Views