Related
I have a table dbo.X with DateTime column lastUpdated and a code product column CodeProd which may have hundreds of records, with CodeProd duplicated because the table is used as "stock history"
My Stored Procedure has parameter #Date, I want to get all CodeProd nearest to that date so for example if I have:
+----------+--------------+--------+
| CODEPROD | lastUpdated | STATUS |
+----------+--------------+--------+
| 10 | 2-1-2019 | C1 |
| 10 | 1-1-2019 | C2 |
| 10 | 31-12-2019 | C1 |
| 11 | 31-12-2018 | C1 |
| 11 | 30-12-2018 | C1 |
| 12 | 30-8-2018 | C3 |
+----------+--------------+--------+
and #Date= '1-1-2019'
I wanna get:
+----+--------------+------+
| 10 | 1-1-2019 | C2 |
| 11 | 31-12-2018 | C1 |
| 12 | 30-8-2018 | C3 |
+----+--------------+------+
How to find it?
You can use TOP(1) WITH TIES to get one row with nearest date for each CODEPROD which should be less than provided date.
Try like following code.
SELECT TOP(1) WITH TIES *
FROM [YourTableName]
WHERE lastupdated <= #date
ORDER BY Row_number()
OVER (
partition BY [CODEPROD]
ORDER BY lastupdated DESC);
You can use apply :
select distinct t.CODEPROD, t1.lastUpdated, t1.STATUS
from table t cross apply
( select top (1) t1.*
from table t1
where t1.CODEPROD = t.CODEPROD and t1.lastUpdated <= #date
order by t1.lastUpdated desc
) t1;
I am looking to gather the TOP diff from the inventory table, where the newcount <> quantity.
Basically, if my inventory count was different than it should have been, I want to search my remaining inventory for the TOP # of missing parts. This brings me back an instock id to ensure that I am removing the oldest parts first.
I could have 900 of these, so I am looking for a sql command that returns the results from partsremainingfifo based on the diff and partnumber in inventory.
select
PartNumber,
Quantity,
NewCount,
diff
from Inventory
where NewCount <> Quantity
+------------+----------+----------+------+
| PartNumber | Quantity | NewCount | diff |
+------------+----------+----------+------+
| 2871451 | 1 | 0 | 1 |
| 4932615 | 6 | 1 | 5 |
+------------+----------+----------+------+
select top 1
id, PartNumber,
PartDescription,
Quantity,
TotalPrice,
Brand,
Location,
Account
from PARTSREMAININGFIFO
where PartNumber = '2871451'
+------+------------+-------------------+----------+------------+---------+----------+----------+
| id | PartNumber | PartDescription | Quantity | TotalPrice | Brand | Location | Account |
+------+------------+-------------------+----------+------------+---------+----------+----------+
| 9183 | 2871451 | AFM DEVICE GASKET | 1 | 19.815225 | CUMMINS | A1 | 6015-Z |
+------+------------+-------------------+----------+------------+---------+----------+----------+
select top 5
id,
PartNumber,
PartDescription,
Quantity,
TotalPrice,
Brand,
Location,
Account
from PARTSREMAININGFIFO
where PartNumber = '4932615'
+------+------------+-----------------+----------+------------+---------+----------+---------+
| id | PartNumber | PartDescription | Quantity | TotalPrice | Brand | Location | Account |
+------+------------+-----------------+----------+------------+---------+----------+---------+
| 3264 | 4932615 | GASKET | 1 | 2.907144 | CUMMINS | A1 | 6015-Z |
| 9780 | 4932615 | GASKET | 1 | 5.053475 | CUMMINS | A1 | 6015-Z |
| 9781 | 4932615 | GASKET | 1 | 5.053475 | CUMMINS | A1 | 6015-Z |
| 9782 | 4932615 | GASKET | 1 | 5.053475 | CUMMINS | A1 | 6015-Z |
| 9783 | 4932615 | GASKET | 1 | 5.053475 | CUMMINS | A1 | 6015-Z |
+------+------------+-----------------+----------+------------+---------+----------+---------+
I understand what you want now, and I think you'll need a cursor. One important note, you must specify an order by when you use TOP unless you don't care what rows come back. Read this article.
Here is how you'd implement this:
--create some sample data that you gave
declare #inventory table ( PartNumber int,
Quantity int,
NewCount int,
diff int)
insert into #inventory
values
(2871451,1,0,1),
(4932615,6,1,5)
declare #PARTSREMAININGFIFO table ( id int,
PartNumber int,
PartDescription varchar(64),
Quantity int,
TotalPrice decimal (8,6),
brand varchar(64),
Location varchar(16),
Account varchar(64))
insert into #PARTSREMAININGFIFO
values
(9183,2871451,'AFM DEVICE GASKET',1,19.815225,'CUMMINS','A1','6015-Z'),
(9183,2871451,'AFM DEVICE GASKET',1,19.815225,'CUMMINS','A2','6015-Z'), --notice the extra (2nd) row here for part 2871451
(9183,2871451,'AFM DEVICE GASKET',1,19.815225,'CUMMINS','A3','6015-Z'), --notice the extra (3nd) row here for part 2871451
(3264,4932615,'GASKET',1,2.907144,'CUMMINS','A1','6015-Z'),
(9780,4932615,'GASKET',1,5.053475,'CUMMINS','A1','6015-Z'),
(9781,4932615,'GASKET',1,5.053475,'CUMMINS','A1','6015-Z'),
(9782,4932615,'GASKET',1,5.053475,'CUMMINS','A1','6015-Z'),
(9783,4932615,'GASKET',1,5.053475,'CUMMINS','A1','6015-Z'),
(9783,4932615,'GASKET',1,5.053475,'CUMMINS','A6','6015-Z') --notice the 6th (extra) row here for part 4932615
--staging table for your results
declare #tempResults table ( id int,
PartNumber int,
PartDescription varchar(64),
Quantity int,
TotalPrice decimal (8,6),
brand varchar(64),
Location varchar(16),
Account varchar(64))
declare cur cursor local fast_forward for
select distinct
PartNumber,
diff
from (select
PartNumber,
Quantity,
NewCount,
diff
from #inventory
where NewCount <> Quantity) x
declare #partNumber int
declare #diff int
open cur
fetch next from cur into #partNumber, #diff
while ##FETCH_STATUS = 0
begin
insert into #tempResults
select top (#diff)
id,
PartNumber,
PartDescription,
Quantity,
TotalPrice,
Brand,
Location,
Account
from #PARTSREMAININGFIFO
where PartNumber = #partNumber
order by Quantity --note you need to specify WHAT you want to order by
fetch next from cur into #partNumber, #diff
end
select *
from #tempResults
order by PartNumber
close cur
deallocate cur
I have a table with a million records. I need to update some columns which are null based on the existing 'not null' records of a particular id based columns. I've tried with one query, it seems to be working fine but I don't have confidence in it that it will be able to update all those 1 million records exactly the way I need. I'm providing you some sample data how my table looks like.Any help will be appreciated
SELECT * INTO #TEST FROM (
SELECT 1 AS EMP_ID,10 AS DEPT_ID,15 AS ITEM_NBR ,NULL AS AMOUNT,NULL AS ITEM_NME
UNION ALL
SELECT 1,20,16,500,'ABCD'
UNION ALL
SELECT 1,30,17,NULL,NULL
UNION ALL
SELECT 2,10,15,1000,'XYZ'
UNION ALL
SELECT 2,30,16,NULL,NULL
UNION ALL
SELECT 2,40,17,NULL,NULL
) AS A
Sample data:
+--------+---------+----------+--------+----------+
| EMP_ID | DEPT_ID | ITEM_NBR | AMOUNT | ITEM_NME |
+--------+---------+----------+--------+----------+
| 1 | 10 | 15 | NULL | NULL |
| 1 | 20 | 16 | 500 | ABCD |
| 1 | 30 | 17 | NULL | NULL |
| 2 | 10 | 15 | 1000 | XYZ |
| 2 | 30 | 16 | NULL | NULL |
| 2 | 40 | 17 | NULL | NULL |
+--------+---------+----------+--------+----------+
Expected result:
+--------+---------+----------+--------+----------+
| EMP_ID | DEPT_ID | ITEM_NBR | AMOUNT | ITEM_NME |
+--------+---------+----------+--------+----------+
| 1 | 10 | 15 | 500 | ABCD |
| 1 | 20 | 16 | 500 | ABCD |
| 1 | 30 | 17 | 500 | ABCD |
| 2 | 10 | 15 | 1000 | XYZ |
| 2 | 30 | 16 | 1000 | XYZ |
| 2 | 40 | 17 | 1000 | XYZ |
+--------+---------+----------+--------+----------+
I tried this but I'm unable to conclude whether it is updating all the 1 million records properly.
SELECT * FROM #TEST T
inner JOIN #TEST T1 ON T1.EMP_ID=T.EMP_ID
WHERE T1.AMOUNT IS NOT NULL
UPDATE T SET AMOUNT=T1.AMOUNT
FROM #TEST T
inner JOIN #TEST T1 ON T1.EMP_ID=T.EMP_ID
WHERE T1.AMOUNT IS not NULL
I have used UPDATE using inner join
UPDATE T
SET T.AMOUNT = X.AMT,T.ITEM_NME=X.I_N
FROM #TEST T
JOIN
(SELECT EMP_ID,MAX(AMOUNT) AS AMT,MAX(ITEM_NME) AS I_N
FROM #TEST
GROUP BY EMP_ID) X ON X.EMP_ID = T.EMP_ID
SELECT * into #Test1
FROM #TEST
WHERE AMOUNT IS NOT NULL
For records validation run this query first
SELECT T.AMOUNT, T1.AMOUNT, T1.EMP_ID,T1.EMP_ID
FROM #TEST T
inner JOIN #TEST1 T1 ON T1.EMP_ID=T.EMP_ID
WHERE T.AMOUNT IS NULL
Begin Trans
UPDATE T
SET T.AMOUNT=T1.AMOUNT, T.ITEM_NME= = T1.ITEM_NME
FROM #TEST T
inner JOIN #TEST1 T1 ON T1.EMP_ID=T.EMP_ID
WHERE T.AMOUNT IS NULL
rollback
SELECT EMP_ID,MAX(AMOUNT) as AMOUNT MAX(ITEM_NAME) as ITEM_NAME
INTO #t
FROM #TEST
GROUP BY EMP_ID
UPDATE t SET t.AMOUNT = t1.AMOUNT, t.ITEM_NAME = t1.ITEM_NAME
FROM #TEST t INNER JOIN #t t1
ON t.emp_id = t1.emp_id
WHERE t.AMOUNT IS NULL and t.ITEM_NAME IS NULL
Use MAX aggregate function to get amount and item name for each employee and then replace null values of amount and item name with those values. For validation use COUNT function to calculate the number of rows with values of amount and item name as null. If the number of rows is zero then table is updated correctly
table:
+-----------+--------------+------------+------------+
| RequestID | RequestStaus | StartDate | EndDate |
+-----------+--------------+------------+------------+
| 1 | pending | 9/1/2015 | 10/2/2015 |
| 1 | in progress | 10/2/2015 | 10/20/2015 |
| 1 | completed | 10/20/2015 | 11/3/2015 |
| 1 | reopened | 11/3/2015 | null |
| 2 | pending | 9/5/2015 | 9/7/2015 |
| 2 | in progress | 9/7/2015 | 9/25/2015 |
| 2 | completed | 9/25/2015 | 10/7/2015 |
| 2 | reopened | 10/10/2015 | 10/16/2015 |
| 2 | completed | 10/16/2015 | null |
+-----------+--------------+------------+------------+
I would like to calculate the days opened but exclude the days between completed and reopened. For example, RequestID 1, the days opened will be (11/3/2015 - 9/1/2015) + (GetDate() - 11/3/2015), for request 2, the total days will be (10/7/2015 - 9/5/2015) + ( 10/16/2015 - 10/10/2015).
The result I want will be something like:
+-----------+-------------------------------+
| RequestID | DaysOpened |
+-----------+-------------------------------+
| 1 | 63 + (getdate() - 11/3/2015) |
| 2 | 38 |
+-----------+-------------------------------+
How do I approach this problem? thank you!
Tested. Works well. :)
Note:
1) I suppose the required result = (FirstCompleteEndDate - PendingStartDate)+(Sum of all the Reopen duration)
2) So I used the self joins. Table b provides the exact completed record which immediately follows the in process record for each RequestID. Table c provides Sum of all the Reopen duration.
--create tbl structure
create table #test (RequestID int, RequestStatus varchar(20), StartDate date, EndDate date)
go
--insert sample data
insert #test
select 1,'pending','09/01/2015','10/2/2015'
union all
select 1,'in progress','10/2/2015','10/20/2015'
union all
select 1,'completed','10/20/2015','11/3/2015'
union all
select 1,'reopened','11/3/2015',null
union all
select 2,'pending','09/05/2015','9/7/2015'
union all
select 2,'in progress','09/07/2015','9/25/2015'
union all
select 2,'completed','9/25/2015','10/7/2015'
union all
select 2,'reopened','10/10/2015','10/16/2015'
union all
select 2, 'completed','10/16/2015','11/12/2015'
union all
select 2,'reopened','11/20/2015',null
select * from #test
--below is solution
select a.RequestID, a.Startdate as [PendingStartDate], b.enddate as [FirstCompleteEndDate], c.startdate as [LatestReopenStartDate],
datediff(day,a.startdate,b.enddate)+c.ReopenDays as [days] from #test a
join (
select *, row_number()over(partition by RequestID,RequestStatus order by StartDate) as rid from #test
) as b
on a.RequestID = b.RequestID
join (
select distinct RequestID, RequestStatus, max(StartDate)over(partition by RequestID,RequestStatus) as StartDate,
Sum(Case when enddate is null then datediff(day,startdate,getdate())
when enddate is not null then datediff(day,startdate,enddate)
end)over(partition by RequestID,RequestStatus) as [ReopenDays]
from #test
where RequestStatus = 'reopened'
) as c
on b.RequestID = c.RequestID
where a.RequestStatus ='pending' and b.RequestStatus = 'completed' and b.rid = 1
Result:
A table (Table1) has the data below:
+-----------+-----------+-----------+---------+
| AccountNo | OldBranch | NewBranch | Balance |
+-----------+-----------+-----------+---------+
| 785321 | 10 | 20 | -200 |
| 785322 | 10 | 20 | 300 |
+-----------+-----------+-----------+---------+
Using the logic :
if the Balance is negative (ie. <0) then NewBranch has to be debited (Dr) and Old Branch has to be credited (Cr);
if the Balance is positive (ie. >0) then OldBranch has to be debited (Dr) and New Branch has to be credited (Cr);
rows as below have to be inserted into another Table (Table2)
+------------+------+--------+--------+
| Account NO | DrCr | Branch | Amount |
+------------+------+--------+--------+
| 785321 | Dr | 20 | 200 |
| 785321 | Cr | 10 | 200 |
| 785322 | Cr | 20 | 300 |
| 785322 | Dr | 10 | 300 |
+------------+------+--------+--------+
What are the possible solutions using a Cursor and otherwise?
Thanks,
You did not provide much in the way of details but something like this should be pretty close.
update nb
set Balance = Balance - ABS(t1.Balance)
from NewBranch nb
join Table1 t1 on t1.AccountNo = nb.AccountNo
where nb.Balance < 0
update ob
set Balance = Balance - ABS(t1.Balance)
from OldBranch ob
join Table1 t1 on t1.AccountNo = ob.AccountNo
where ob.Balance > 0
You absolutely dont need a cursor, just a set of insert statements
INSERT INTO Table2 (AccountNo,DrCr,Branch,Amount)
SELECT AccountNo,'Dr',IIF(Balance<0,NewBranch,OldBranch),IIF(balance<0,-1*balance,balance) FROM Table1
UNION ALL
SELECT AccountNo,'Cr',IIF(Balance>0,NewBranch,OldBranch),IIF(balance<0,-1*balance,balance) FROM Table1
declare #t table (Accountno int,
OldBranch INT,
NewBranch int,
Balance int)
insert into #t (Accountno,
OldBranch,
NewBranch,
Balance)
values (785321,10,20,200),
(785322,10,20,300)
select Accountno,Y.CRDR,Y.Branch,Y.Amount from #t CROSS APPLY
(Select 'Dr' AS CRDR,OldBranch AS Branch,Balance As Amount
UNION ALL
Select 'Cr',NewBranch,Balance)y