Selection of records on bases of date - sql

Below is my query and I want the selection of Qty from those SKU which is going to expire first. Please help me how can I do this.
DECLARE #Data table (Id int identity(1,1)
, SKU varchar(10)
, QtyRec int
, Expiry date
, Rec date)
DECLARE #Qty int = 20
INSERT #Data VALUES
('001A', 5 ,'2017-01-15','2015-11-14'),
('001A', 8 ,'2017-01-10','2015-11-14'),
('001A', 6 ,'2015-12-15','2015-11-15'),
('001A', 25,'2016-01-01','2015-11-16'),
('001A', 9 ,'2015-12-20','2015-11-17')
;WITH sumqty AS
(
SELECT *, SUM(QtyRec) OVER (PARTITION BY SKU ORDER BY Id) AS TotalQty FROM #Data
)
,takeqty AS (
SELECT *,
CASE
WHEN #Qty >= TotalQty THEN QtyRec
ELSE #Qty - ISNULL(LAG(TotalQty) OVER (PARTITION BY SKU ORDER BY Id), 0)
END AS TakeQty
FROM sumqty
)
SELECT * FROM takeqty WHERE TakeQty > 0

There are many possible outcomes depends on your question:
If you want to order result-set based on Expiry date ascending order, then Use ORDER BY Expiry at the end of CTEs query. Or select top expire: Use SELECT TOP(1) ROW_NUMBER() OVER(ORDER BY Expiry) AS 'SN' instead of SELECT ROW_NUMBER() OVER(ORDER BY Expiry) AS 'SN'
DECLARE #Data table (Id int identity(1,1)
, SKU varchar(10)
, QtyRec int
, Expiry date
, Rec date)
DECLARE #Qty int = 20
INSERT #Data VALUES
('001A', 5 ,'2017-01-15','2015-11-14'),
('001A', 8 ,'2017-01-10','2015-11-14'),
('001A', 6 ,'2015-12-15','2015-11-15'),
('001A', 25,'2016-01-01','2015-11-16'),
('001A', 9 ,'2015-12-20','2015-11-17');
WITH sumqty AS
(
SELECT *, SUM(QtyRec) OVER (PARTITION BY SKU ORDER BY Id) AS TotalQty FROM #Data
)
,takeqty AS (
SELECT *,
CASE
WHEN #Qty >= TotalQty THEN QtyRec
ELSE #Qty - ISNULL(LAG(TotalQty) OVER (PARTITION BY SKU ORDER BY Id), 0)
END AS TakeQty
FROM sumqty
)
SELECT ROW_NUMBER() OVER(ORDER BY Expiry) AS 'SN'
, SKU
, QtyRec
, Expiry
, Rec
, TotalQty
, TakeQty
FROM takeqty WHERE TakeQty > 0
ORDER BY Expiry;

Related

INSERT INTO #tmp from CTE query

I want to be able to insert the results of this CTE query into a temp table so I can sum the Total column.
CREATE TABLE #tmp
(
SerialNumber NVARCHAR(50),
StartDateTime NVARCHAR(50),
EndDateTime NVARCHAR(50),
Total NVARCHAR(50)
)
;WITH cte1 AS
(
SELECT
*,
CASE
WHEN Temperature > #maxthreshold AND LAG(Temperature) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime) IS NULL THEN 1
WHEN Temperature <= #maxthreshold AND LEAD(Temperature) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime) > #maxthreshold THEN 1
WHEN Temperature <= #maxthreshold AND LAG(Temperature) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime) > #maxthreshold THEN 1
END AS chg
FROM
[RawData]
WHERE
SerialNumber = #_Serial
AND CombineDateTime BETWEEN #_DateFrom AND #_DateTo
), cte2 AS
(
SELECT
*,
SUM(chg) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime) AS grp
FROM
cte1
)
INSERT INTO #tmp
SELECT
SerialNumber,
MIN(CombineDateTime) AS StartDateTime,
MAX(CombineDateTime) AS EndDateTime,
DATEDIFF(SECOND, MIN(CombineDateTime), MAX(CombineDateTime)) / 60.0 AS 'Total'
FROM
cte2
GROUP BY
SerialNumber, grp
HAVING
MAX(Temperature) > #maxthreshold)
SELECT *
FROM #tmp
DROP TABLE #tmp
I have tried putting the insert in various places, but it does not insert, I have tried the following answers. I am confused as to why the insert won't work as it is outside of the recursion.
Answer 1
Answer 2
TIA

SQL number greater than select results

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

SQL Query-Group by and filters

I have the table as shown in below image.
I am trying to get the latest status_id, grouped by team_id and based on max of created_date.
--Latest status for each team based on created date
SELECT *
FROM ProductionHistory
WHERE created_Date IN (
SELECT MAX(created_Date)
FROM ProductionHistory
GROUP BY TeamID
)
That's fine, here is the result:
My questions are:
How to ignore the assigned_to null then find latest record for team?
When there is only one record with assigned_to null for team, let's consider that.
For example: for Team_id 5 there is only one record with assigned_to null, we don't have any other record for team_id 5 with assigned_to set some value.
So we have consider this.
For team id 3 query result should ignore the record 4 (though max date), query result should contain record 2.
Here is the final result I am expecting:
Try this:
DECLARE #t TABLE
(
TicketID INT ,
TeamID INT ,
StatusID INT ,
created_Date DATETIME ,
Assigned_to NVARCHAR(MAX)
)
INSERT #t
VALUES ( 10000, 2, 7, '2015-03-26 01:48:00.000', 'W3ER45' ),
( 10000, 3, 7, '2015-03-26 05:48:00.000', 'YU67IO' ),
( 10000, 2, 9, '2015-03-26 03:48:00.000', 'HJKO98' ),
( 10000, 3, 9, '2015-03-27 03:48:00.000', NULL ),
( 10000, 4, 11, '2015-03-23 03:48:00.000', 'GHR67' ),
( 10000, 5, 11, '2015-03-27 02:12:56.910', NULL );
;
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY TicketID, TeamID ORDER BY CASE
WHEN Assigned_to IS NULL
THEN 1
ELSE 0
END, created_Date DESC ) AS rn
FROM #t
)
SELECT TicketID ,
TeamID ,
StatusID ,
created_Date ,
Assigned_to
FROM cte
WHERE rn = 1
Output:
TicketID TeamID StatusID created_Date Assigned_to
10000 2 9 2015-03-26 03:48:00.000 HJKO98
10000 3 7 2015-03-26 05:48:00.000 YU67IO
10000 4 11 2015-03-23 03:48:00.000 GHR67
10000 5 11 2015-03-27 02:12:56.910 NULL
Try this answer.I did it with cursor
DECLARE #t TABLE ( TicketID INT
, TeamID INT
, StatusID INT
, created_Date DATETIME
, Assigned_to NVARCHAR(MAX) )
DECLARE cur CURSOR READ_ONLY FAST_FORWARD
FOR SELECT [TeamID]
FROM TT
DECLARE #i int
OPEN cur
FETCH NEXT FROM cur INTO #i
WHILE ##FETCH_STATUS=0
BEGIN
IF (SELECT COUNT_BIG([TeamID])
FROM TT
WHERE [TeamID]=#i)>1
BEGIN
INSERT INTO #T
SELECT TOP 1 *
FROM [dbo].[TT]
WHERE [TeamID]=#i AND [Assigned_to] IS NOT NULL
ORDER BY [created_Date] DESC
END
ELSE
BEGIN
INSERT INTO #T
SELECT *
FROM [dbo].[TT]
WHERE [TeamID]=#i
END
FETCH NEXT FROM cur INTO #i
END
SELECT TicketID
, TeamID
, StatusID
, Assigned_to
, created_Date
FROM #T
GROUP BY TicketID
, TeamID
, StatusID
, created_Date
, Assigned_to
CLOSE cur
DEALLOCATE cur

Increase the performance of an inventory (FIFO) query

My goal is to get the price from item which goes into stock and put the price into out item by (FIFO order by TranDate), then calculate the total price of any line of production (" lineid ").
This is what I have done
-- temp table for result
declare #Test table ( stockID int , OriQty decimal(16,2) ,inuse decimal(16,2) , price decimal(16,2) , lineid int , Inid int )
declare #StockIn table (ID int , StockID int ,qty decimal(16,2),Price decimal(16,2), tranDate Date , running int)
insert into #StockIn(ID , StockID , qty , Price , tranDate , running) values
(1,1 , 15 , 430 , '2014-10-09' , 1),
(2,1 , 10 , 431, '2014-12-09' , 2),
(3,1 , 15 , 432, '2015-02-02' , 3),
(4,2 , 15 , 450, '2014-08-05' , 1),
(5,2 , 6 , 450, '2014-10-09' , 2),
(6,2 , 15 , 452, '2015-02-02' , 3)
-- lineid = line production
declare #StockOut table (ID int , StockID int ,qty decimal(16,2), lineid int, tranDate Date)
insert into #StockOut(ID , StockID ,qty , lineid, tranDate )
values
(1,1 , 20 , 2, '2014-10-10'),
(2,1 , 10 , 4, '2014-12-20'),
(3,2 , 12 , 8, '2014-10-01'),
(4,2 , 3 , 8, '2014-10-01') ;
DECLARE #intFlag INT
SET #intFlag = 1 -- initial of loop
WHILE (#intFlag <= (Select Max(ID) from #StockOut) )
BEGIN
declare #stockID int
declare #ids table (ID int , Inuse decimal(16,2))
declare #lineid int
declare #qtyToRemove decimal(16,2) -- get qty from #StockOut
--get data from #StockOut row by row
select #stockID = StockID , #qtyToRemove = qty , #lineid = lineid from #StockOut where ID = #intFlag;
with cte as (
select *, sum(qty) over (order by tranDate ASC , qty DESC , tranDate ASC Rows UNBOUNDED PRECEDING) - #qtyToRemove
as Total FROM #StockIn Where stockID = #stockID )
-- running FIFO from #StockIn and update QTy when stock is running out
, RunningFIFO as (
select cte.StockID , cte.qty AS OriginalQty , Case when
case when 0 > total then cte.qty else cte.qty-total End > 0 then case when 0 > total then cte.qty else cte.qty-total End else 0 End As Inuse
, cte.Price , #lineid AS lineid , id
from cte
)
-- insert result into result table
insert into #test (stockID , OriQty ,inuse , cte.Price , lineid ,Inid ) OUTPUT inserted.Inid , inserted.inuse into #ids select * from RunningFIFO Where Inuse > 0
UPDATE #StockIn set qty = qty - inuse from #ids A inner join #StockIn B on A.ID = b.ID
SET #intFlag = #intFlag + 1
END
Select sum(inuse * price) AS total , lineid from #Test group by lineid
But when data are more than a thousand, this query runs super slow.
How could I increase the performance of this query?

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