Selection within table for new column - sql

I have the table pricedata (see attached file). I want to add two extra columns to this table (MinPrice of Competitor and CompetitorID of MinPrice). I wrote a code to get the column MinPrice of Competitor, BUT I have no idea how to get second column, any help ????
Code:
select a.ValuationDate, a.shop, a.Itemcode, a.OwnPrice,
a.[sales price competitor], a.[competitor ID], b.MinPrice
from [PriceTable] a
inner join
(select ValuationDate, Shop, ItemCode,
min([sales price competitor]) as MinPrice
FROM [PriceTable]
group by ValuationDate, Shop, ItemCode) b
on a.ValuationDate = b.ValuationDate
and a.Shop = b.Shop
and a.ItemCode = b.ItemCode
Actual Table:
Required Table:

Here you go. Hope this helps.
select
a.ValuationDate,
a.shop
a.Itemcode,
a.OwnPrice,
a.[sales price competitor],
a.[competitor ID],
b.MinPrice ,
MINCOMPID.[competitor ID] AS 'CompetitorID of MinPrice'
from [PriceTable] a
inner join
(
select ValuationDate, Shop, ItemCode, min([sales price competitor]) as MinPrice FROM [PriceTable]
group by ValuationDate, Shop, ItemCode
) b
on a.ValuationDate=b.ValuationDate and a.Shop=b.Shop and a.ItemCode=b.ItemCode
INNER JOIN [PriceTable] AS MINCOMPID
ON MINCOMPID.ValuationDate=b.ValuationDate and MINCOMPID.Shop=b.Shop and MINCOMPID.ItemCode=b.ItemCode AND MINCOMPID.[sales price competitor]=b.MinPrice

Look at (not tested). A common way to get the row with min/max value is SELECT TOP(1) .. ORDER BY .. DESC/ASC
select a.ValuationDate, a.shop, a.Itemcode, a.OwnPrice,
a.[sales price competitor], a.[competitor ID],
c.MinPrice, c.[competitor ID]
from [PriceTable] a
cross apply
(SELECT TOP(1) b.[competitor ID]
b.[sales price competitor] as MinPrice
FROM [PriceTable] b
WHERE a.ValuationDate = b.ValuationDate
and a.Shop = b.Shop
and a.ItemCode = b.ItemCode
ORDER BY b.[sales price competitor] DESC) c

Related

SQL query: SUM(Quantity)

I'm trying to build a simple SQL query for an item availability check. My aim is to query the items whose total/summed quantity exceeds the stock level. This is what my table (simplified example) looks like:
LineNumber
Item
Quantity
StockQuantity
1
Banana
1
1
2
Apple
1
1
3
Strawberry
1
1
4
Banana
1
1
I have tried it with the following query, but it doesn't work:
SELECT
T1.[LineNumber], T1.[Item],
SUM(T1.[Quantity]), T1.[Stockquantity]
FROM
Table T1
WHERE
T1.[Quantity] > T1.[Stockquantity]
GROUP BY
T1.[LineNumber], T1.[Item], T1.[Quantity], T1.[Stockquantity]
Does anyone have any advice or tips for me on how I should do this query so that the total/summed quantities per line are compared with the stock quantity and not just the individual/single quantities per line with the stock quantity?
Thank you very much for your help in advance.
Given your extended information in this post: https://stackoverflow.com/a/71452446/1690217 the query you are looking for is this:
WITH TotalsLookup as (
SELECT T1.[VisOrder] as [VisOrder], T1.[U_position] as [ItemGroup-LineNumber]
, T0.[DocNum] as [DocNumber], T2.[InvntItem], T1.[ItemCode] as [Itemcode]
, T1.[Quantity], T1.[OpenCreQty] as [openQuantity]
, T2.[OnHand] as [StockQuantity]
, SUM(T1.[Quantity]) OVER (PARTITION BY T1.[ItemCode] ORDER BY T1.[VisOrder]) AS RunningTotal
FROM OQUT T0
INNER JOIN QUT1 T1 ON T0.[DocEntry] = T1.[DocEntry]
INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode]
)
SELECT VisOrder, [ItemGroup-LineNumber], DocNumber, Itemcode, Quantity, openQuantity, StockQuantity, RunningTotal
FROM TotalsLookup
WHERE DocNumber = '332050' AND [InvntItem] = 'Y' AND RunningTotal > StockQuantity
Original Post
Your example is possibly oversimplified, If StockQuantity is the result of a lookup into an inventory, so that in the example we can say the following:
Total stock on Hand of Bananas is 1
And then if you are expecting LineNumber 4 to be picked up because this line will make the SUM of Bananas greater than the total stock on hand of Bananas... then you need a Running Total of the Item records in this list:
WITH TotalsLookup as (
SELECT
T1.[LineNumber], T1.[Item],
T1.[Quantity], T1.[StockQuantity],
SUM (T1.[Quantity]) OVER (PARTITION BY Item ORDER BY LineNumber) AS RunningTotal
FROM
[Table] T1
)
SELECT *
FROM TotalsLookup
WHERE RunningTotal > StockQuantity;
LineNumber
Item
Quantity
Stockquantity
RunningTotal
4
Banana
1
1
2
See this Fiddle that covers a few variants of this query and will give you a playground to practice: http://sqlfiddle.com/#!18/a95bb/2
The origin of StockQuantity can itself have a significant impact on the performance and other query options that might be viable, I call this out so that you can be mindful of this when you apply this logic into your application domain, if StockQuantity is not a static value, but is itself an aggregate then that may impact how the comparison should be performed.
You can refer to aggregates of a GROUP BY in the having clause
SELECT
T1.[Item],
SUM(T1.[Quantity]) As TotalQuantity,
MAX(T1.[Stockquantity]) AS StockLevel
FROM
Table T1
GROUP BY
T1.[Item]
HAVING
SUM(T1.[Quantity]) > MAX(T1.[Stockquantity])
This assumes that the Stockquantity is the same for all occurrences of a product.
The WHERE clause is executed before grouping, the HAVING clause after grouping.
If you need the line numbers, then you can use the STRING_AGG aggregate function to join the line numbers into a single string per group
SELECT STRING_AGG(T1.[LineNumber], ', ') As LineNumbers, ...
your SQL modified code(SQL code didn't work) that does not provide a single output
SELECT linenumber,
a.item,
quantity,
SumQuantity,
stockquantity
FROM table A
JOIN(SELECT item,
Sum(quantity) SumQuantity,
max(stockquantity) stockquantity
FROM table C
GROUP BY item) B
ON A.item = B.item
WHERE SumQuantity> stockquantity
ouput
linenumber
item
quantity
quantity2
stockquantity
1
Banana
1
2
1
4
Banana
1
2
1
However I use the follwing query
SELECT String_agg(linenumber, ',') LineNumbers,
a.item,
quantity,
SumQuantity,
stockquantity
FROM table A
JOIN(SELECT item,
Sum(quantity) SumQuantity
max(stockquantity) stockquantity
FROM table C
GROUP BY item) B
ON A.item = B.item
WHERE SumQuantity> stockquantity
GROUP BY a.item,
quantity,
SumQuantity,
stockquantity
that bring following result
LineNumbers
Item
Quantity
SumQuantity
StockQuantity
1,4
Banana
1
2
1
Thank you all for your effort and suggestions for solutions. I have tried to incorporate them all. A few of them worked. With others I still have a few problems:
#Chris Schaller
I like you solution a lot! But in my non-simplified, real SQL code, there are item groups that the PARTITION function cannot cope with. My result with your solution is therefore as follows.
However, I will continue to work on it. Thanks!
WITH TotalsLookup as (
SELECT T1.[VisOrder] as 'VisOrder', T1.[U_position] as 'ItemGroup-LineNumber', T0.[DocNum] as 'DocNumber', T1.[ItemCode] as 'Itemcode', T1.[Quantity] as 'Quantity', T1.[OpenCreQty] as 'openQuantity', T2.[OnHand] as 'StockQuantity', SUM(T1.[Quantity]) OVER (PARTITION BY T1.[ItemCode] ORDER BY T1.[VisOrder]) AS RunningTotal
FROM OQUT T0
INNER JOIN QUT1 T1 ON T0.[DocEntry] = T1.[DocEntry]
INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode]
WHERE T0.[DocNum] = '332050' AND T2.[InvntItem] = 'Y'
)
SELECT *
FROM TotalsLookup
WHERE RunningTotal > Quantity
Output: here
#RF1991
I have also tried to implement your solution, but it has not really worked so far. I am still looking for the mistake. Thanks for the help!
SELECT T1.[U_position], T1.[ItemCode], T1.[Quantity], T1.[OpenCreQty], T2.[OnHand]
FROM OQUT T0
INNER JOIN QUT1 T1 ON T0.[DocEntry] = T1.[DocEntry]
INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode]
JOIN(SELECT T1.[ItemCode], SUM(T1.[Quantity]) as 'SumQuantity', MAX(T2.[OnHand]) as 'Stockquantity' FROM OQUT T0 INNER JOIN QUT1 T1 ON T0.[DocEntry] = T1.[DocEntry] INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode] GROUP BY T1.[ItemCode]) B
ON T1.[ItemCode] = B.[ItemCode]
WHERE SumQuantity > stockquantity AND T0.[DocNum] = '332050' AND T2.[InvntItem] = 'Y'
#Oliver Jacot-Descombes
It works. Thank you very much!

SQL: How to find the MAX value/price of a particular item?

I am new to SQL and was wondering if anyone could guide me.
Here is my code and table output:
Code
Prices that are lower than 2.25 are appearing. I only want the 2.25 (highest) values.
I've tried removing the MAX in the select statement, removing the grouping,and replacing the WHERE statement with
WHERE Price = (
SELECT MAX(Price)
FROM tblPurchaseOrderLine
)
AND tblProduct.Description LIKE 'Alpine Small Pot'
buuut it gave no output.
SOLUTION:
SELECT tblPurchaseOrder.PONumber 'PO Number',
tblVendor.Name 'Vendor Name',
tblProduct.ProductID 'Product ID',
tblProduct.Description,
MAX(tblPurchaseOrderLine.Price)'Price'
FROM tblPurchaseOrder
INNER JOIN tblVendor
ON tblVendor.VendorID = tblPurchaseOrder.VendorID
INNER JOIN tblPurchaseOrderLine
ON tblPurchaseOrderLine.PONumber = tblPurchaseOrder.PONumber
INNER JOIN tblProduct
ON tblProduct.ProductID = tblPurchaseOrderLine.ProductID
WHERE Price = (SELECT MAX(Price)
FROM tblPurchaseOrderLine
WHERE tblProduct.ProductID = tblPurchaseOrderLine.ProductID)
AND tblProduct.Description LIKE 'Alpine Small Pot'
GROUP BY tblPurchaseOrder.PONumber,tblVendor.Name,tblProduct.ProductID,tblProduct.Description
Thank you! I got it working
What you want in your case is a correlated subquery:
from tblPurchaseOrderLine t1
WHERE Price = (
SELECT MAX(Price)
FROM tblPurchaseOrderLine t2
where t1.product_id = t2.product_id
)
AND tblProduct.Description LIKE 'Alpine Small Pot'
There is a better way to do this:
You can do this using TOP 1 with window function in order clause:
select top 1 with ties t.*
from your_table t
where tblProduct.Description LIKE 'Alpine Small Pot'
order by row_number() over (
partition by product_id
order by price desc
);

Easy Left Join SQL Syntax

New to SQL and want to complete a LEFT JOIN.
I have two seperate tables with the below code:
SELECT
StockCode, SalesOrder, SUM(OrderQty)
FROM
dbo.IopSalesPerf
WHERE
dbo.IopSalesPerf.CustRequestDate BETWEEN '2017-07-01' AND '2017-07-31'
AND EntrySystemTime = 1
AND Warehouse = '01'
AND StockCode = '001013'
GROUP BY
StockCode,SalesOrder
ORDER BY
StockCode ASC
SELECT
SalesOrder, SUM(NetSalesValue), SUM(QtyInvoiced)
FROM
ArTrnDetail
GROUP BY
SalesOrder
I would like to LEFT JOIN the last table onto the first using SalesOrder as the joining column. Can anyone assist with the syntax?
Simpliest way would be:
SELECT * FROM
(
SELECT StockCode,SalesOrder,sum(OrderQty)
FROM dbo.IopSalesPerf
WHERE dbo.IopSalesPerf.CustRequestDate between '2017-07-01' and '2017-07-31'
and EntrySystemTime = 1 and Warehouse = '01' and StockCode = '001013'
GROUP BY StockCode,SalesOrder
Order BY StockCode ASc
) AS A
LEFT JOIN
(
SELECT SalesOrder,sum(NetSalesValue),sum(QtyInvoiced)
FROM ArTrnDetail
Group by SalesOrder
) AS B
ON A.SalesOrder = B.SalesOrder

How can i get the sum of the values between two dates

my query is
select
ir.ProductId,
sum(ir.IssueQuantity) as 'Quantity',
p.ProductName,
ir.IssueDate,
ir.ReturnDate
from Product.IssueReturn ir
join Company.Product p on p.ProductId=ir.ProductId
group by ir.ProductId,p.ProductName,ir.IssueDate,ir.ReturnDate
SELECT
ProductId , PrdName ,
SUM(IssueQuantity) IssueQuantity ,
MIN(IssueDate) IssueDate,MAX(ReturnDATE) ReturnDATE
FROM Table1 join Table2 on ProductId = ProductId
GROUP BY ProductId , PrdName
Remove date field column in selection.
select ir.ProductId,sum(ir.IssueQuantity)as 'Quantity',p.ProductName
--,ir.IssueDate,ir.ReturnDate
from Product.IssueReturn ir join Company.Product p on p.ProductId=ir.ProductId
group by ir.ProductId,p.ProductName
--,ir.IssueDate,ir.ReturnDate

Is there any way to write this query without using WITH Clause

Screenshot of table account:
[]
Screenshot of table trandetails:
[
Problem: Write a query to display the total number of withdrawals and total number of deposits being done by customer whose registration is C00001. Give the count an alias name of Trans_Count.
I want to reduce line of code for the above question
I have written this query
Code:
with t as
(
select acnumber,transaction_type,count(transaction_type) as trans_type
from trandetails as t
group by transaction_type,acnumber
)
,c as
(
select c.custid,c.acnumber
from account as c
where custid like 'C00001'
)
select c.custid,t.transaction_type,t.trans_type
from t inner join c on c.acnumber = t.acnumber
SELECT c.custid,
t.transaction_type,
t.trans_type
FROM account AS c
INNER JOIN(
SELECT acnumber,
transaction_type,
COUNT(transaction_type) AS trans_type
FROM trandetails
GROUP BY transaction_type,
acnumber ) t ON c.acnumber = t.acnumber
WHERE c.custid LIKE 'C00001';
If acnumber is unique in account, then it would be further simpler:
SELECT c.custid,
t.transaction_type,
COUNT(t.transaction_type) AS trans_type
FROM account AS c
INNER JOIN trandetails AS t ON c.acnumber = t.acnumber
WHERE c.custid LIKE 'C00001'
GROUP BY c.custid,
t.transaction_type;
Try this query
SELECT c.custid, t.transaction_type, t.trans_type
FROM (SELECT acnumber, transaction_type, COUNT(transaction_type) AS trans_type
FROM trandetails
GROUP BY transaction_type, acnumber
) t
INNER JOIN (SELECT custid, acnumber
FROM account
WHERE custid LIKE 'C00001'
) c
ON c.acnumber = t.acnumber
See if that is what you want:
select a.custid
,t.transaction_type
,sum(t.transaction_amount) amount
from account a
,trandetails t
where t.acnumber = a.acnumber
and a.custid = 'C00001'
group by a.custid
,t.transaction_type;
Here is an example with conditional aggregation:
select a.custid,
sum(case when d.transaction_type = 'Deposit' then 1 end) as DepositCount,
sum(case when d.transaction_type = 'Withdrawal' then 1 end) as WithdrawalCount,
from account a
join trandetails d on a.acnumber = d.acnumber
where a.custid = 'C00001'
group by a.custid
You can always use subquery insted of CTE
select c.custid,
t.transaction_type,
t.trans_type
from account c
inner join (
select s.acnumber,
s.transaction_type,
count(s.transaction_type) as trans_type
from trandetails as s
group by s.transaction_type,
s.acnumber) t on c.acnumber = t.acnumber
where c.custid = 'C00001'
Probably you have to use either s.custid = 'C00001' or something like that s.custid like '%C00001%'. like is used to search inside of some string, not for direct comparision for equality.
Tip 1: Avoid subquery if possible
Tip 2: Do not use LIKE clause if not required - in your case seems that '=' will do the job - here is a small testing sample:
DECLARE #account TABLE (
custid VARCHAR(20),
acnumber VARCHAR(20)
)
DECLARE #trandetails TABLE (
acnumber VARCHAR(20),
transaction_type VARCHAR(20)
)
INSERT INTO
#account
VALUES
('C00001', 'A00001'),
('C00002', 'A00002')
INSERT INTO
#trandetails
VALUES
('A00001', 'Withdrawal'),
('A00001', 'Deposit'),
('A00002', 'Deposit')
SELECT
acc.custid,
td.transaction_type,
count(td.transaction_type) AS trans_cnt
FROM
#account acc
INNER JOIN #trandetails td
ON acc.acnumber = td.acnumber
WHERE
acc.custid = 'C00001'
GROUP BY
acc.custid,
td.acnumber,
td.transaction_type