SQL number greater than select results - sql

I'm struggling to think of a way to do this with T-SQL.
I have a table which is populated every 5 seconds with the prices of three currencies (GBP, EUR & USD)
I've created a trigger (after insert), which selects the last 5 records entered for a given currency:
SELECT TOP 5 Price from dbo.prices where coin='GBP' ORDER BY Date Desc
I want to determine if the last inserted currency price is greater than the selected 5 above, how do i do this?
Thanks

As I guess: there cant be two entries for the same currency at one time. Only one insert per currency per some time (5sec). So this should fit yours requirements:
declare #prices table ([Date] int IDENTITY(1,1) primary key, Price float, coin varchar(3));
insert into #prices (coin, Price) values
('GBP', 3.20),('EUR', 3.14),('USD', 3.14),
('GBP', 3.17),('EUR', 3.16),('USD', 3.11),
('GBP', 3.14),('EUR', 3.13),('USD', 3.16),
('GBP', 3.15),('EUR', 3.12),('USD', 3.17),
('GBP', 3.16),('EUR', 3.17),('USD', 3.11),
('GBP', 3.15),('EUR', 3.14),('USD', 3.12),
('GBP', 3.19),('EUR', 3.14),('USD', 3.16)
select
case
when NEW.Price > PREV.Price Then 'yes'
else 'No'
end as CURR_JUMP_UP
from
(
select top 1 COALESCE(Price,0) Price, [Date]
from #prices where coin='GBP' order by [Date] desc
) NEW
cross apply
(
select MAX(Price) Price from
(
select top 5 Price
from #prices
where coin='GBP' and [Date]<NEW.[Date]
order by [Date] desc
) t
) PREV

Try this query:
DECLARE #AmountLastFiveEntry DECIMAL= (SELECT TOP 5 SUM(Price) FROM dbo.prices WHERE
ID NOT IN (SELECT TOP 1 ID
FROM dbo.prices where coin='GBP' ORDER BY Date Desc) where coin='GBP' ORDER BY Date Desc)
IF #AmountLastFiveEntry<(SELECT TOP 1 Price
FROM dbo.prices where coin='GBP' ORDER BY Date Desc)
BEGIN
SELECT #AmountLastFiveEntry --To do task
END

Trigger part is confusing
This will report if the latest price is higher (or equal) to the largest of the prior 5.
declare #currency table (iden int IDENTITY(1,1) primary key, exchange smallint, coin tinyint);
insert into #currency (coin, exchange) values
(1, 1)
, (1, 2)
, (1, 3)
, (1, 4)
, (1, 5)
, (1, 6)
, (2, 1)
, (2, 2)
, (2, 3)
, (2, 4)
, (2, 5)
, (2, 3);
select cccc.coin, cccc.exchange
, case when cccc.rn = cccc.rne then 'yes'
else 'no'
end as 'high'
from ( select ccc.iden, ccc.coin, ccc.exchange, ccc.rn
, ROW_NUMBER() over (partition by ccc.coin order by ccc.exchange desc, ccc.rn) rne
from ( select cc.iden, cc.coin, cc.exchange, cc.rn
from ( select c.iden, c.coin, c.exchange
, ROW_NUMBER() over (partition by coin order by iden desc) as rn
from #currency c
) cc
where cc.rn <= 6
) ccc
) cccc
where cccc.rn = 1
order by cccc.coin

Related

Group/Summarize each row with removal row if total quantity is 0

How to group/summarize as example image below.
The same data will be grouped based on Date and Item columns.
The quantity will be sum.
If the negative quantity is more than total quantity of the min date (total qty = 0), that row will be removed.
This condition will continue for the next min date as well.
In this case 1-Jan-2020 and 2-Jan-2020 will be removed because it negative quantity is more than total of those 2 days.
In case you want sample table, please use script below.
CREATE TABLE #temp_table(
[id] [int] IDENTITY(1,1) NOT NULL,
[trans_date] [date] NOT NULL,
[item] [nvarchar](40) NOT NULL,
[qty] [int] NOT NULL,
)
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '1-Jan-2020', 'Item A', 2 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '2-Jan-2020', 'Item A', 4 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '3-Jan-2020', 'Item B', 1 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '3-Jan-2020', 'Item A', 3 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '4-Jan-2020', 'Item A', -1 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '5-Jan-2020', 'Item A', -6 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '6-Jan-2020', 'Item A', 4 )
SELECT * FROM #temp_table
DROP TABLE #temp_table
My 1st attempt was
select
trans_date
, item
, SUM(qty)
from temp_table
group BY
trans_date
, item
My 2nd attempt, this attempt is feel like I'm lacking of some condition to reduce the next row when I first row is 0.
select
temp_table.trans_date
, temp_table.item
, SUM(temp_table.qty) + SUM(neg_table.neg_qty)
from temp_table
OUTER APPLY (
SELECT ISNULL( SUM(neg.qty), 0) AS neg_qty FROM pca_temp_table neg
WHERE 1=1
and temp_table.item = neg.item
and neg.qty < 0
) as neg_table
WHERE qty > 0
group BY
trans_date
, item
Hope this query works fine for you:
select MAX(CASE WHEN Quantity>0 THEN DATE ELSE NULL END), ITEM, SUM(Quantity)
from #T
group BY ITEM

SQL Server : loop through one table and get the sum till threshold value is reached and update the sum value in another table

I have two tables:
Sales table:
Returns table:
I have to loop through the Sales table and get sum of all the Qty based on Material+Batch+customer combination until it exceeds the value of Return_qty, and update the Summed value in the Returns table.
This is the desired output:
As you can see, from the Sales table until Sales_Invoice 4 only it considered as it exceeded the value of return_Qty.
What I have tried till now?
I have tried to use while loop to loop through and calculate running total. But its not working out. Maybe approach is wrong.
Any inputs will be highly appreciated.
Try this:
DECLARE #Sales TABLE
(
[Sales_Invoice] SMALLINT
,[Invoice_Date] DATE
,[Material] VARCHAR(3)
,[Batch] VARCHAR(2)
,[Customer] VARCHAR(4)
,[Qty] SMALLINT
);
DECLARE #Returns TABLE
(
[Return_Invoice] SMALLINT
,[Invoice_Date] DATE
,[Material] VARCHAR(3)
,[Batch] VARCHAR(2)
,[Customer] VARCHAR(4)
,[Return_Qty] SMALLINT
,[Sales_Qty] SMALLINT
);
INSERT INTO #Sales ([Sales_Invoice], [Invoice_Date], [Material], [Batch], [Customer], [Qty])
VALUES (1, '2019-06-07', 'AB1', 'B1', 'B001', 50)
,(2, '2019-06-07', 'AB1', 'B1', 'B001', 20)
,(3, '2019-06-06', 'AB1', 'B1', 'B001', 25)
,(4, '2019-06-06', 'AB1', 'B1', 'B001', 11)
,(5, '2019-06-06', 'AB1', 'B1', 'B001', 20)
,(6, '2019-06-01', 'BA2', 'C1', 'Y001', 100);
INSERT INTO #Returns ([Return_Invoice], [Invoice_Date], [Material], [Batch], [Customer], [Return_Qty])
VALUES (212, '2019-06-08', 'AB1', 'B1', 'B001', 100);
WITH DataSource AS
(
SELECT [Material], [Batch], [Customer]
,SUM([Qty]) OVER (PARTITION BY [Material], [Batch], [Customer] ORDER BY [Sales_Invoice] ASC) AS [Return_Qty]
FROM #Sales
)
UPDATE #Returns
SET [Sales_Qty] = DS.[Return_Qty]
FROM #Returns R
INNER JOIN
(
SELECT [Material], [Batch], [Customer]
,MIN([Return_Qty]) AS [Return_Qty]
FROM DataSource
WHERE [Return_Qty] >= 100
GROUP BY [Material], [Batch], [Customer]
) DS
ON R.[Material] = DS.[Material]
AND R.[Batch] = DS.[Batch]
AND R.[Customer] = DS.[Customer];
SELECT *
FROM #Returns;
If you want to be more dynamical, you can use the following:
WITH DataSource AS
(
SELECT [Material], [Batch], [Customer]
,SUM([Qty]) OVER (PARTITION BY [Material], [Batch], [Customer] ORDER BY [Sales_Invoice] ASC) AS [Return_Qty]
FROM #Sales
)
UPDATE #Returns
SET [Sales_Qty] = DataSource.[Return_Qty]
FROM #Returns R
CROSS APPLY
(
SELECT DS.[Material], DS.[Batch], DS.[Customer]
,MIN(DS.[Return_Qty]) AS [Return_Qty]
FROM DataSource DS
WHERE DS.[Return_Qty] >= R.[Return_Qty]
AND R.[Material] = DS.[Material]
AND R.[Batch] = DS.[Batch]
AND R.[Customer] = DS.[Customer]
GROUP BY [Material], [Batch], [Customer]
) DataSource;
you should really show your while statement in your post - can you do that please?
I think a common table expression using recursion is a good solution for you. something along the lines of ...
;
WITH
cte1 AS
(
SELECT
RANK() OVER
(ORDER BY S.Material, S.Batch, S.Customer) GroupId,
RANK() OVER
(
PARTITION BY S.Material, S.Batch, S.Customer,
ORDER BY S.INVOICE_Date) Seqn,
S.Material, S.Batch, S.Customer, S.qty, R.Return_qty
FROM
Sales S
JOIN
Returns R
ON S.Material = R.Material AND S.Batch = R.Batch AND S.Customer = R.Customer
),
cte2 AS
(
SELECT
GroupId, Seqn,Material, Batch, Customer, qty AS TriggeringQty, Return_qty
FROM cte1
WHERE seqn =1
UNION ALL
SELECT
cte1.GroupId, cte1.Seqn, cte1.Material, cte1.Batch, cte1.Customer,
cte1.qty + cte2.qty, cte1.Return_qty
FROM cte2
JOIN cte1
ON cte1.GroupId = cte2.GroupID AND cte1.seqn = cte2.seqn+1
WHERE
cte2.qty < 100 AND cte1.seqn + cte2.seqn+1 >= Return_qty )
UPDATE R
SET R.Sales_qty = cte2.triggeringqty
FROM Returns R
JOIN cte2 S ON
S.Material = R.Material AND S.Batch = R.Batch AND S.Customer = R.Customer
WHERE cte2.triggeringqty >= 100;
Sorry I haven't tried the above so probably won't run, but hopefully you see what's happening.

How can I only pull back the latest result in SQL?

I'm struggling to find out how to only return the latest iteration of the claimtid in the result set. I'm using this query:
SELECT
claimid, paiddate
CASE
WHEN actid = '119' THEN 'Channel Exception'
WHEN actid = '127' THEN 'Rejected'
WHEN actid = '128' THEN 'Accepted'
WHEN actid = '130' THEN 'Adjustment Complete'
WHEN actid = '133' THEN 'Channel Ready'
END AS [Status]
FROM
Encounter
WHERE
claimtid LIKE '173225AR0%' OR claimtid LIKE '197565GL0%' OR
claimtid LIKE '293215QW0%' OR claimtid LIKE
ORDER BY
claimtid
This query returns the following result:
|claimtid |paiddt |Status |
-+----------+----------+-------------------+
1|173225AR00|2017-03-01|Adjustment Complete|
2|173225AR01|2017-04-11|Accepted |
3|197565GL00|2017-03-17|Accepted |
4|197565GL01|2017-03-19|Adjustment Complete|
5|197565GL02|2017-04-01|Rejected |
6|293215QW00|2017-04-19|Adjustment Complete|
7|293215QW01|2017-04-23|Accepted |
I'm not sure what I can add to my query so that the results will only bring back lines 2, 5, and 7. My actual query contains produces more rows in the result.
This is only an example, but is accurate to the situation. I'll need to pull back more than 3 rows, but it needs to be the latest iteration.
Each additional iteration makes the last number in the claimtid go up by one. I won't know how many iterations there are of each claimtid.
Try this, but I am not sure of the performance penalty for using a string for claimtid as in your case:
SELECT claimid, paiddate
FROM
Encounter
WHERE claimtid IN (
SELECT MAX(paiddt), claimtid
FROM Encounter
GROUP BY SUBSTRING (claimtid, 6, 8)
) t
Assuming you can count on the paiddate field to know the most recent record.
If you can't separate the two fields of the claim ID into separate columns of the data table itself, you can pull them apart in a query, to allow you to use the max() aggregate to find the largest value of the second field.
select
claim,
paiddate,
CASE
WHEN actid = '119' THEN 'Channel Exception'
WHEN actid = '127' THEN 'Rejected'
WHEN actid = '128' THEN 'Accepted'
WHEN actid = '130' THEN 'Adjustment Complete'
WHEN actid = '133' THEN 'Channel Ready'
END AS [Status]
from
(
select
left(claimid, 6) as claim,
max(right(claimid,4)) as seq,
from
Encounter
group by
left(claimid, 6)
) as ms
inner join Encounter as e
on e.claimid = ms.claim + ms.seq;
This should do the trick...
IF OBJECT_ID('tempdb..#ClaimData', 'U') IS NOT NULL
DROP TABLE #ClaimData;
CREATE TABLE #ClaimData (
RN INT NOT NULL IDENTITY(1,1),
claimtid CHAR(10) NOT NULL,
paiddt DATE NOT NULL,
[Status] VARCHAR(20) NOT NULL
);
INSERT #ClaimData (claimtid, paiddt, Status) VALUES
('173225AR00', '2017-03-01', 'Adjustment Complete'),
('173225AR01', '2017-04-11', 'Accepted'),
('197565GL00', '2017-03-17', 'Accepted'),
('197565GL01', '2017-03-19', 'Adjustment Complete'),
('197565GL02', '2017-04-01', 'Rejected'),
('293215QW00', '2017-04-19', 'Adjustment Complete'),
('293215QW01', '2017-04-23', 'Accepted');
--SELECT * FROM #ClaimData cd;
--=========================================================
SELECT TOP 1 WITH TIES
cd.RN, cd.claimtid, cd.paiddt, cd.Status
FROM
#ClaimData cd
CROSS APPLY ( VALUES (SUBSTRING(cd.claimtid, 1, 6), SUBSTRING(cd.claimtid, 7, 4)) ) sc (Claim_1, Claim_2)
ORDER BY
ROW_NUMBER() OVER (PARTITION BY sc.Claim_1 ORDER BY sc.Claim_2 DESC);
Results...
RN claimtid paiddt Status
----------- ---------- ---------- --------------------
2 173225AR01 2017-04-11 Accepted
5 197565GL02 2017-04-01 Rejected
7 293215QW01 2017-04-23 Accepted
Edit...
A slightly better performing solution that produces the same results...
SELECT
RN = CAST(SUBSTRING(MAX(bv.BinaryValue), 39, 4) AS INT),
claimtid = CAST(SUBSTRING(MAX(bv.BinaryValue), 1, 10) AS CHAR(10)),
paiddt = CAST(SUBSTRING(MAX(bv.BinaryValue), 11, 8) AS DATE),
Status = CAST(SUBSTRING(MAX(bv.BinaryValue), 19, 20) AS VARCHAR(20))
FROM
#ClaimData cd
CROSS APPLY ( VALUES (CAST(cd.claimtid AS BINARY(10)) + CAST(cd.paiddt AS BINARY(8)) + CAST(cd.Status AS BINARY(20)) + CAST(cd.RN AS BINARY(4))) ) bv (BinaryValue)
GROUP BY
SUBSTRING(cd.claimtid, 1, 6);
Try this, assuming you can't have a early claimtid with a later paiddt:
IF OBJECT_ID('tempdb..#ClaimData') IS NOT NULL
DROP TABLE #ClaimData
CREATE TABLE #ClaimData (
ID INT NOT NULL IDENTITY(1,1)
, claimtid CHAR(10) NOT NULL
, paiddt DATE NOT NULL
, [Status] VARCHAR(20) NOT NULL
)
INSERT #ClaimData (claimtid, paiddt, Status) VALUES
('173225AR00', '2017-03-01', 'Adjustment Complete')
,('173225AR01', '2017-04-11', 'Accepted')
,('197565GL00', '2017-03-17', 'Accepted')
,('197565GL01', '2017-03-19', 'Adjustment Complete')
,('197565GL02', '2017-04-01', 'Rejected')
,('293215QW00', '2017-04-19', 'Adjustment Complete')
,('293215QW01', '2017-04-23', 'Accepted')
SELECT
ID
, x.claimtid
, x.paiddt
, x.Status
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY LEFT(Claimtid, LEN(Claimtid) - 2) ORDER BY paiddt DESC) RN
, *
FROM #ClaimData
) x
WHERE x.RN = 1
Otherwise change RN to ROW_NUMBER() OVER (PARTITION BY LEFT(Claimtid, LEN(Claimtid) - 2) ORDER BY RIGHT(Claimtid, 2) DESC) RN

Price calculation based on the unit entered

Table Schema:
CREATE TABLE [dbo].[TblPriceDetails](
[PriceID] [int] IDENTITY(1,1) NOT NULL,
[VID] [int] NOT NULL,
TypeID int not null,
[RangeStart] [decimal](18, 3) NOT NULL,
[RangeEnd] [decimal](18, 3) NOT NULL,
[Price] [decimal](18, 2) NOT NULL,
[ExtraLoad] [decimal](18, 3) NULL,
[ExtraPrice] [decimal](18, 2) NULL
)
GO
Sample Data
Insert into dbo.TblPriceDetails values (1,1, 0,0.250,10,0,0)
Insert into dbo.TblPriceDetails values (1,1, 0.251,0.500,15,0.500,15)
Insert into dbo.TblPriceDetails values (1,1, 3,5,40,1,25)
GO
Insert into dbo.TblPriceDetails values (1,2, 0,0.250,15,0,0)
Insert into dbo.TblPriceDetails values (1,2, 0.251,0.500,20,0.500,20)
Insert into dbo.TblPriceDetails values (1,2, 3,5,50,1,30)
GO
Expected Output:
For VID = 1 and TypeID = 1 and a given value 0.300
As the input unit falls between RangeStart 0.251 and RangeEnd 0.500
the resultant price will be 15
For VID = 1 and TypeID = 1 and a given value 0.600
As per the data until 0.500 the price is 15 and for every extraLoad
of upto 0.500 its another 15. So the final price will be 30
For VID = 1 and TypeID = 1 and given value 1.500
As per the data until 0.500 the price is 15. For every extra 0.500
its another 15, so for the remaining 1 unit it would be 15 * 2. The
final price will be 45
For VID = 1 and TypeID = 1 and given value 5.5
As per the data until 5.000 the price is 40. For every extra 1 unit its another 25, so the final price will be 65
Need help in writing a query for this. Unlike my other questions I don't have a query yet to show what I have come up with till now. As of now I am not able to frame a logic and come up with a generic query for this.
It looks like you are looking to calculate postage price. The trick is to join on the RangeStart of the next weight tier. LEAD will help you do that:
;WITH
AdjustedPriceDetails AS
(
SELECT VID, TypeID, RangeStart, RangeEnd, Price, ExtraLoad, ExtraPrice
, ISNULL(LEAD(RangeStart, 1) OVER (PARTITION BY VID, TypeID ORDER BY RangeStart), 1000000) AS NextRangeStart
FROM TblPriceDetails
)
SELECT T.*
, A.Price + IIF(T.Value <= A.RangeEnd, 0, CEILING((T.Value - A.RangeEnd) / A.ExtraLoad) * A.ExtraPrice)
AS FinalPrice
FROM #TestData T
INNER JOIN AdjustedPriceDetails A ON A.RangeStart <= T.Value AND T.Value < A.NextRangeStart
Explanation:
LEAD(RangeStart, 1) OVER (PARTITION BY VID, TypeID ORDER BY RangeStart) gets the RangeStart of the next row that has the same VID and TypeID
You will eventually reach the highest weight tier. So ISNULL(..., 1000000) make this tier appear to end at 1M. The 1M is just a stand-in for infinity.
Edit: if you want to make this work with SQL Server 2008, change the CTE:
;WITH
tmp AS
(
SELECT VID, TypeID, RangeStart, RangeEnd, Price, ExtraLoad, ExtraPrice
, ROW_NUMBER() OVER (PARTITION BY VID, TypeID ORDER BY RangeStart) AS RowNumber
FROM TblPriceDetails
),
AdjustedPriceDetails AS
(
SELECT T1.VID, T1.TypeID, T1.RangeStart, T1.RangeEnd, T1.Price, T1.ExtraLoad, T1.ExtraPrice
, ISNULL(T2.RangeStart, 1000000) AS NextRangeStart
FROM tmp T1
LEFT JOIN tmp T2 ON T1.VID = T2.VID AND T1.TypeId = T2.TypeID AND T1.RowNumber + 1 = T2.RowNumber
)
If you wonder what #TestData is (you may not need it)
CREATE TABLE #TestData
(
VID int
, TypeID int
, Value float
)
INSERT INTO #TestData
( VID, TypeID, Value)
VALUES ( 1, 1, 0.3 )
, ( 1, 1, 0.6 )
, ( 1, 1, 1.5 )
, ( 1, 1, 5.5 )

Selection One Entry Only As Non Zero In SQl Select

I have a scenario where I have to select multiple rows from table, I have multiple rows of one record but with different status,
at times I have two identical rows with identical data for status < for that case I canted to select Non zero for the first occurrence and set 0 for the remaining occurrences.
Below is the Image to show and I have marked strike-out and marked 0 for the remaining occurrence.
And body could suggest better SQL Query:
Here is the Query: I am getting zero value for status 1 for ID =1 but I need to show first as regular and then 0 if that status repeats again.
CREATE TABLE #Temp
(ID INT,
ItemName varchar(10),
Price Money,
[Status] INT,
[Date] Datetime)
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,2,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-28')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-26')
INSERT INTO #Temp VALUES(2,'DEF',25,3,'2014-08-27')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-28')
INSERT INTO #Temp VALUES(3,'GHI',30,1,'2014-08-27')
SELECT CASE WHEN Temp.Status = 1 THEN
0
ELSE
Temp.Price END AS Price,
* FROM (SELECT * FROM #Temp) Temp
DROP TABLE #Temp
Here is the result:
You might modify your inner select using Row_Number() and set price to Zero for RowNumber > 1.
SELECT CASE WHEN Temp.RowNumber > 1 THEN
0
ELSE
Temp.Price END AS Price,
* FROM (
SELECT *,Row_Number() over (PARTITION by ID,Status ORDER BY ID,Date) AS 'RowNumber'
FROM #Temp
) Temp
Order by ID,Date
You can try this:
;WITH DataSource AS
(
SELECT RANK() OVER (PARTITION BY [ID], [ItemName], [Price], [Status] ORDER BY Date) AS [RankID]
,*
FROM #Temp
)
SELECT [ID]
,[ItemName]
,IIF([RankID] = 1, [Price], 0)
,[Status]
,[Date]
FROM DataSource
ORDER BY [ID]
,[Date]
Here is the output:
please try this below code . it is working for me.
CREATE TABLE #Temp
(ID INT,
ItemName varchar(10),
Price Money,
[Status] INT,
[Date] Datetime)
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,2,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-28')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-26')
INSERT INTO #Temp VALUES(2,'DEF',25,3,'2014-08-27')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-28')
INSERT INTO #Temp VALUES(3,'GHI',30,1,'2014-08-27')
select *,case when a.rn=1 and status!=2 then price else 0 end as price from
(select *,ROW_NUMBER() over(partition by status,date order by date asc) rn from #Temp) a
order by ItemName asc
You can do this with UNION:
SELECT * FROM #Temp t
WHERE NOT EXISTS
(SELECT * FROM #Temp
WHERE t.id = id and t.status = status and t.date < date)
UNION ALL
SELECT ID, ItemName, 0 as Price, status, date
WHERE EXISTS
(SELECT * FROM #Temp
WHERE t.id = id and t.status = status and t.date < date)
Or subquery:
SELECT CASE
WHEN (SELECT COUNT(*)
FROM #Temp
WHERE t.id = id and t.status = status
and t.date > date) > 1 THEN 0 ELSE price END as NewPrice, t.*
FROM #Temp t
Or possibly RANK() function:
SELECT CASE
WHEN RANK() OVER (PARTITION BY id, status ORDER BY date) > 1
THEN 0 ELSE Price END,
t.*
FROM #Temp t