Query to change the values of the column? - sql

I have a table like this which contains a column number Order
FunctionID Name ParentFunctionID OrderNo Enabled ControllerName ActionName
1 Nikhil 0 10 1 nik
2 Sahil 0 20 1 sah
3 With 2 10 1 sah Withsnew
4 User 2 20 1 sah users
5 Pen 2 10 0 sah pend
44 User Summary 2 210 1 sah usersummary
45 Summary 2 230 1 sah summary
46 Hourly 1 231 1 nik hourly
47 Code 1 232 1 nik code
I want the Table like
FunctionID Name ParentFunctionID OrderNo Enabled ControllerName ActionName
1 Nikhil 0 1 1 nik
2 Sahil 0 2 1 sah
3 With 2 1 1 sah Withsnew
4 User 2 2 1 sah users
5 Pen 2 3 0 sah pend
44 User Summary 2 4 1 sah usersummary
45 Summary 2 5 1 sah summary
46 Hourly 1 1 1 nik hourly
47 Code 1 2 1 nik code

USE THE ROWNUM FEATURE:
SELECT
FunctionID ,
Name ,
ParentFunctionID,
ROWNUM AS ORDER_NO,
Enabled,
ControllerName ,
ActionName
FROM TABLE NAME;
If you want rownumbers to reset based on particular conditions, use PARTITION along with ROW_NUMBER AS:
SELECT
FunctionID ,
Name ,
ParentFunctionID,
ROW_NUMBER() OVER (PARTITION BY ParentFunctionID ORDER BY FunctionID ) AS ORDER_NO,
Enabled,
ControllerName ,
ActionName
FROM TABLE NAME;

you can use ROW_NUMBER and partition by ParentFunctionID just like this
SELECT FunctionID, Name, ParentFunctionID
, ROW_NUMBER() OVER(PARTITION BY ParentFunctionID ORDER BY FunctionID) OrderNo
, [Enabled], ControllerName, ActionName
FROM TABLENAME
this will return the resultset if you want to update you can modify the script.
I hope this is helpful.

You can use ROW_NUMBER (Transact-SQL) to enumerate your rows partitioned by ParentFunctionID ordered by FunctionID to get the result you want.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table YourTable
(
FunctionID int,
Name varchar(20),
ParentFunctionID int,
OrderNo int,
Enabled bit,
ControllerName varchar(20),
ActionName varchar(20)
)
go
insert into YourTable values
(1 , 'Nikhil ', 0, 10 , 1, 'nik', ' '),
(2 , 'Sahil ', 0, 20 , 1, 'sah', ' '),
(3 , 'With ', 2, 10 , 1, 'sah', 'Withsnew '),
(4 , 'User ', 2, 20 , 1, 'sah', 'users '),
(5 , 'Pen ', 2, 10 , 0, 'sah', 'pend '),
(44, 'User Summary', 2, 210, 1, 'sah', 'usersummary'),
(45, 'Summary ', 2, 230, 1, 'sah', 'summary '),
(46, 'Hourly ', 1, 231, 1, 'nik', 'hourly '),
(47, 'Code ', 1, 232, 1, 'nik', 'code ')
Query 1:
with C as
(
select OrderNo,
row_number() over(partition by ParentFunctionID order by FunctionID) as rn
from YourTable
)
update C
set OrderNo = rn
select *
from YourTable
Results:
| FUNCTIONID | NAME | PARENTFUNCTIONID | ORDERNO | ENABLED | CONTROLLERNAME | ACTIONNAME |
|------------|--------------|------------------|---------|---------|----------------|-------------|
| 1 | Nikhil | 0 | 1 | 1 | nik | |
| 2 | Sahil | 0 | 2 | 1 | sah | |
| 3 | With | 2 | 1 | 1 | sah | Withsnew |
| 4 | User | 2 | 2 | 1 | sah | users |
| 5 | Pen | 2 | 3 | 0 | sah | pend |
| 44 | User Summary | 2 | 4 | 1 | sah | usersummary |
| 45 | Summary | 2 | 5 | 1 | sah | summary |
| 46 | Hourly | 1 | 1 | 1 | nik | hourly |
| 47 | Code | 1 | 2 | 1 | nik | code |

Related

Leaderboard toplist with current userid in center - SQL query

I have the following table:
+---------+------------+----------+-------+
| userId | campaignId | countryId| points|
+---------+------------+----------+-------+
| 10 | 1 | 101 | 72 |
| 3 | 1 | 101 | 30 |
| 6 | 1 | 101 | 72 |
| 4 | 1 | 101 | 49 |
| 1 | 1 | 101 | 53 |
| 8 | 1 | 101 | 67 |
| 5 | 1 | 101 | 6 |
| 7 | 1 | 101 | 87 |
| 2 | 1 | 101 | 41 |
| 11 | 1 | 101 | 76 |
| 9 | 1 | 101 | 50 |
+---------+------------+----------+-------+
I have already created a leaderboard toplist with a query like this:
select
RANK() OVER(order by T.points desc) AS rowRank,
T.UserID, T.points
from table as T
where T.campaignId=#campaignId
OFFSET (#page-1)*#limit ROWS FETCH NEXT #limit ROWS ONLY
Above query returns a regular toplist from top to bottom.
However, next requirement is to create a leaderboard toplist that returns current user Id rank + the above 2 ranked users + the 2 below ranked users, in total 5 users should be listed with current user in the center.
So additional input parameters would be:
set #userId = 8 // current user where leader board should center around
set #maxTopLimit = 2 // include 2 users ranked above current user
set #maxBottomLimit = 2 // include 2 users ranked below current user
The leaderboard returned should look like this with userId 8 in the center
+---------+------------+----------+-------+---------|
| userId | campaignId | countryId| points| rowRank |
+---------+------------+----------+-------+---------+
| 11 | 1 | 101 | 76 | 3 |
| 10 | 1 | 101 | 72 | 4 |
#####|###### 8 | 1 #########|##### 101 |### 67 |## 5 ####|########
| 9 | 1 | 101 | 50 | 6 |
| 2 | 1 | 101 | 49 | 7 |
+---------+------------+----------+-------+------+--+
How do I write a SQL query that behaves like this?
Move the ranking results in a subquery or common table expression.
with cte_rank as (...)
Select the target user.
from cte_rank cr where cr.UserId = #userId
Join the target row with all rows in the defined interval.
join cte_rank cr2 on cr2.RowRank >= cr.RowRank - #before and cr2.RowRank <= cr.RowRank + #after
Select all rows from the interval.
select cr2.*
Sample data
create table CampaignPoints
(
UserId int,
CampaignId int,
CountryId int,
Points int
);
insert into CampaignPoints (UserId, CampaignId, CountryId, Points) values
(10, 1, 101, 72),
( 3, 1, 101, 30),
( 6, 1, 101, 72),
( 4, 1, 101, 49),
( 1, 1, 101, 53),
( 8, 1, 101, 67),
( 5, 1, 101, 6),
( 7, 1, 101, 87),
( 2, 1, 101, 41),
(11, 1, 101, 76),
( 9, 1, 101, 50);
Solution
declare #userId int = 8;
declare #before int = 2;
declare #after int = 2;
with cte_rank as
(
select cp.UserId,
cp.CampaignId,
cp.CountryId,
cp.Points,
rank() over(order by cp.Points desc) as RowRank
from CampaignPoints cp
)
select cr2.*
from cte_rank cr
join cte_rank cr2
on cr2.RowRank >= cr.RowRank - #before
and cr2.RowRank <= cr.RowRank + #after
where cr.UserId = #userId
order by cr2.RowRank;
Result
UserId CampaignId CountryId Points RowRank
------ ---------- --------- ------ -------
10 1 101 72 3
6 1 101 72 3
8 1 101 67 5
1 1 101 53 6
9 1 101 50 7
Fiddle to see things in action.

Redshift or ANY SQL: Update a table with with similar rows whose times are within 30 seconds

I've got this table:
prod | customer | city | num | time | isextra
-----+----------+---------+------+--------------------+-------
1 | Jim | Venice | 5 |2015-08-27 1:10:00 | 0
1 | Jim | Venice | 5 |2015-08-27 1:10:15 | 0
1 | Jim | Venice | 5 |2015-08-27 1:10:28 | 0
4 | Jane | Vienna | 8 |2018-06-04 2:20:43 | 0
4 | Jane | Vienna | 8 |2018-06-04 2:20:43 | 0
4 | Jane | Vienna | 8 |2018-06-04 2:20:49 | 0
4 | Jane | Vienna | 8 |2018-06-04 2:30:55 | 0
7 | Jack | Vilnius | 4 |2015-09-15 2:20:55 | 0
7 | Jake | Vigo | 9 |2018-01-01 10:20:05 | 0
7 | Jake | Vigo | 2 |2018-01-01 10:20:25 | 0
Now take all rows that are similar by prod, customer, city, num then any row whose time is within 30 seconds of the first in the group, its 'isextra' field is UPDATED to 1, and have this be the result:
prod | customer | city | num | time | isextra
-----+----------+---------+------+--------------------+-------
1 | Jim | Venice | 5 |2015-08-27 1:10:00 | 0
1 | Jim | Venice | 5 |2015-08-27 1:10:15 | 1
1 | Jim | Venice | 5 |2015-08-27 1:10:28 | 1
4 | Jane | Vienna | 8 |2018-06-04 2:20:43 | 0
4 | Jane | Vienna | 8 |2018-06-04 2:20:43 | 1
4 | Jane | Vienna | 8 |2018-06-04 2:20:49 | 1
4 | Jane | Vienna | 8 |2018-06-04 2:30:55 | 0
7 | Jack | Vilnius | 4 |2015-09-15 2:20:55 | 0
7 | Jake | Vigo | 9 |2018-01-01 10:20:05 | 0
7 | Jake | Vigo | 2 |2018-01-01 10:20:25 | 0
Here's the table and data:
create table mytable (prod int, customer varchar, city varchar, num int, time timestamp, isextra smallint);
insert into mytable values (1, 'Jim', 'Venice', 5, '2015-08-27 1:10:00', 0);
insert into mytable values (1, 'Jim', 'Venice', 5, '2015-08-27 1:10:15', 0);
insert into mytable values (1, 'Jim', 'Venice', 5, '2015-08-27 1:10:28', 0);
insert into mytable values (4, 'Jane', 'Vienna', 8, '2018-06-04 2:20:43', 0);
insert into mytable values (4, 'Jane', 'Vienna', 8, '2018-06-04 2:20:43', 0);
insert into mytable values (4, 'Jane', 'Vienna', 8, '2018-06-04 2:20:49', 0);
insert into mytable values (4, 'Jane', 'Vienna', 8, '2018-06-04 2:30:55', 0);
insert into mytable values (7, 'Jack', 'Vilnius', 4, '2015-09-15 2:20:55', 0);
insert into mytable values (7, 'Jake', 'Vigo', 9, '2018-01-01 10:20:05', 0);
insert into mytable values (7, 'Jake', 'Vigo', 2, '2018-01-01 10:20:25', 0);
All I have is this so far:
UPDATE mytable
SET isextra = 1
FROM (
select *,
row_number() over (partition by prod, customer, city, num order by time asc)
as t from mytable
) AS sequence
Stuck here...
Any ideas appreciated, thanks!
I would write a select using window functions as:
select t.*,
(case when time > min_time and
time < dateadd(minute, 30, min_time)
then 1 else 0
end) as is_extra
from (select t.*,
min(time) over (partition by prod, customer, city, num) as min_time
from t
) t;
The only issue are the duplicate times at the same row. We could fix that as:
select t.*,
(case when time > min_time and time < dateadd(minute, 30, min_time) and seqnum <> 0
then 1 else 0
end) as is_extra
from (select t.*,
min(time) over (partition by prod, customer, city, num) as min_time,
row_number() over (partition by prod, customer, city, num order by time) as seqnum
from t
) t;
Unfortunately, turning this into an update is really tricky because of the exact duplicate rows in your example.
If you have a unique id on each row, then you can turn this into an update:
update t
set t.is_extra = tt.new_is_extra
from (select t.*,
(case when time > min_time and time < dateadd(minute, 30, min_time) and seqnum <> 0
then 1 else 0
end) as new_is_extra
from (select t.*,
min(time) over (partition by prod, customer, city, num) as min_time,
row_number() over (partition by prod, customer, city, num order by time) as seqnum
from t
) t
) tt
where t.id = tt.id
Don't know if this flies in PostgreSQL 8.0 (redshift), but it's worth a try:
update mytable a
set isextra = 1
from (
select prod, customer, city, num, min(time) as mintime
from mytable
group by prod, customer, city, num
) b
where a.prod = b.prod
and a.customer = b.customer
and a.city = b.city
and a.num = b.num
and a.time <= b.mintime + interval '30 seconds'
and a.time <> b.mintime;
Result:
prod customer city num time isextra
---- -------- ---- --- --------------------- -------
1 Jim Venice 5 2015-08-27 01:10:00.0 0
1 Jim Venice 5 2015-08-27 01:10:15.0 1
1 Jim Venice 5 2015-08-27 01:10:28.0 1
4 Jane Vienna 8 2018-06-04 02:20:43.0 0
4 Jane Vienna 8 2018-06-04 02:20:43.0 0
4 Jane Vienna 8 2018-06-04 02:20:49.0 1
4 Jane Vienna 8 2018-06-04 02:30:55.0 0
7 Jack Vilnius 4 2015-09-15 02:20:55.0 0
7 Jake Vigo 2 2018-01-01 10:20:25.0 0
7 Jake Vigo 9 2018-01-01 10:20:05.0 0

Cleaning up duplicate chronological values

I am trying to clean up some chronological data to remove duplicate chronological data.
Example Table:
+--------+------------+----------------+
| emp_id | department | effective_date |
+--------+------------+----------------+
| 1 | 50 | 2015-04-01 |
| 1 | 50 | 2015-05-22 |
| 1 | null | 2015-07-04 |
| 1 | null | 2015-07-24 |
| 1 | null | 2015-07-30 |
| 1 | 50 | 2015-09-07 |
| 1 | 50 | 2016-01-16 |
| 1 | null | 2016-04-23 |
| 2 | 60 | 2015-01-20 |
| 2 | 60 | 2015-11-22 |
| 2 | 60 | 2016-07-20 |
| 3 | 50 | 2015-04-02 |
| 3 | 50 | 2015-07-15 |
| 3 | 60 | 2016-01-25 |
+--------+------------+----------------+
As you can see, the same individual with the same department may have the same department but multiple effective_dates. I want to clean this up with a query to only have the first date for each department change. However, I don't want to remove instances where someone went from department 50 to null then back to 50, as those are actual changes in position.
Example Output:
+--------+------------+----------------+
| emp_id | department | effective_date |
+--------+------------+----------------+
| 1 | 50 | 2015-04-01 |
| 1 | null | 2015-07-04 |
| 1 | 50 | 2015-09-07 |
| 1 | null | 2016-04-23 |
| 2 | 60 | 2015-01-20 |
| 3 | 50 | 2015-04-02 |
| 3 | 60 | 2016-01-25 |
+--------+------------+----------------+
How can I achieve this?
My solution is
DECLARE #myTable TABLE (emp_id INT, department INT, effective_date DATE);
INSERT INTO #myTable VALUES
(1, 50 , '2015-04-01'),
(1, 50 , '2015-05-22'),
(1, null, '2015-07-04'),
(1, null, '2015-07-24'),
(1, null, '2015-07-30'),
(1, 50 , '2015-09-07'),
(1, 50 , '2016-01-16'),
(1, null, '2016-04-23'),
(2, 60 , '2015-01-20'),
(2, 60 , '2015-11-22'),
(2, 60 , '2016-07-20'),
(3, 50 , '2015-04-02'),
(3, 50 , '2015-07-15'),
(3, 60 , '2016-01-25')
;WITH T AS (
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY emp_id ORDER BY effective_date)
FROM #myTable
)
SELECT T1.emp_id, T1.department, T1.effective_date
FROM
T T1
LEFT JOIN T T2 ON T1.emp_id = T2.emp_id AND T1.RN -1 = T2.RN
WHERE (CASE WHEN ISNULL(T1.department,'') = ISNULL(T2.department,'') THEN 1 ELSE 0 END) = 0
ORDER BY T1.emp_id, T1.RN
Result:
emp_id department effective_date
----------- ----------- --------------
1 50 2015-04-01
1 NULL 2015-07-04
1 50 2015-09-07
1 NULL 2016-04-23
2 60 2015-01-20
3 50 2015-04-02
3 60 2016-01-25
(7 row(s) affected)
For delete the duplicate values:
;WITH T AS (
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY emp_id ORDER BY effective_date)
FROM #myTable
)
DELETE T1
FROM
T T1
LEFT JOIN T T2 ON T1.emp_id = T2.emp_id AND T1.RN -1 = T2.RN
WHERE ( CASE
WHEN ISNULL(T1.department,'') <> ISNULL(T2.department,'') THEN 1
ELSE 0 END ) = 0
An alternative for where clause
WHERE ( CASE WHEN T1.department <> T2.department
OR (T1.department IS NULL AND T2.department IS NOT NULL)
OR (T2.department IS NULL AND T1.department IS NOT NULL)
THEN 1 ELSE 0 END ) = 0
This was tougher than expected:
declare #temp as table (emp_id int, department int,effective_date date)
insert into #temp
values
(1,50,'2015-04-01')
, (1,50,'2015-05-22')
, (1, null ,'2015-07-04')
, (1, null ,'2015-07-24')
, (1, null ,'2015-07-30')
, (1,50,'2015-09-07')
, (1,50,'2016-01-16')
, (1, null ,'2016-04-23')
, (2,60,'2015-01-20')
, (2,60,'2015-11-22')
, (2,60,'2016-07-20')
, (3,50,'2015-04-02')
, (3,50,'2015-07-15')
, (3,60,'2016-01-25')
;with cte as
(
--Please not I am changing null to -1 for comparison
select emp_id,isnull(department,-1) department,effective_date
,row_number() over (partition by emp_id order by effective_date) rn
from #temp
)
,cte2 as
(
--Compare to next record
select cte.*
,ctelast.emp_id cte2Emp
,ctelast.department cte2dept
,ctelast.effective_date cte2ED
,isSame = case when cte.department=ctelast.department then 1 else 0 end
from cte
join cte ctelast
on cte.emp_id=ctelast.emp_id and cte.rn = ctelast.rn-1
)
/*
Result of above:
emp_id department effective_date rn cte2Emp cte2dept cte2ED isSame
1 50 2015-04-01 1 1 50 2015-05-22 1
1 50 2015-05-22 2 1 -1 2015-07-04 0
1 -1 2015-07-04 3 1 -1 2015-07-24 1
1 -1 2015-07-24 4 1 -1 2015-07-30 1
1 -1 2015-07-30 5 1 50 2015-09-07 0
1 50 2015-09-07 6 1 50 2016-01-16 1
1 50 2016-01-16 7 1 -1 2016-04-23 0
2 60 2015-01-20 1 2 60 2015-11-22 1
2 60 2015-11-22 2 2 60 2016-07-20 1
3 50 2015-04-02 1 3 50 2015-07-15 1
3 50 2015-07-15 2 3 60 2016-01-25 0
*/
--Now you want both the first record and then any changes
select emp_id,department,effective_date from cte2 where rn=1
union all
select cte2emp,cte2dept,cte2.cte2ED from cte2 where isSame=0
order by 1,3
/*
result:
emp_id department effective_date
1 50 2015-04-01
1 -1 2015-07-04
1 50 2015-09-07
1 -1 2016-04-23
2 60 2015-01-20
3 50 2015-04-02
3 60 2016-01-25
*/

Get permutations of ordered sets of N values

I have a table that consists of a set codes for an item. Each code's group is defined by group_id. The table is defined as follows:
CREATE TABLE item_code (
id int PRIMARY KEY NOT NULL IDENTITY (1,1),
item_id int DEFAULT NULL,
group_id int NOT NULL,
code varchar(50) NOT NULL
);
CREATE TABLE groups (
id int PRIMARY KEY NOT NULL IDENTITY (1,1),
name varchar(50) NOT NULL,
order int NOT NULL
)
For each item_id in the table, I need to select 1 code from each group_id ordered by the group's order. For example:
INSERT INTO groups (id, name, order) VALUES (1, 'one', 10), (2, 'two', 20), (3, 'three', 30);
INSERT INTO item_code (item_id, group_id, [code])
VALUES
(99, 1, 'code1-1'),
(99, 1, 'code1-2'),
(99, 2, 'code2-1'),
(99, 2, 'code2-2'),
(99, 3, 'code3-1'),
(100,1, 'another-code');
would result in the set:
item_id code_combination
99 "code1-1"
99 "code1-2"
99 "code2-1"
99 "code2-2"
99 "code3-1"
99 "code1-1, code2-1"
99 "code1-1, code2-2"
99 "code1-2, code2-1"
99 "code1-2, code2-2"
99 "code1-1, code3-1"
99 "code1-2, code3-1"
99 "code2-1, code3-1"
99 "code2-2, code3-1"
99 "code1-1, code2-1, code3-1"
99 "code1-2, code2-1, code3-1"
99 "code1-1, code2-2, code3-1"
99 "code1-2, code2-2, code3-1"
100 "another-code"
The order of the actual results does not matter. I included a row for item_id == 100 just to show that results for all item_id should be included.
What I've done so far:
I've build a CTE that gets combinations of codes, but it does not respect item_id, groups or order and that's where I'm stuck:
;WITH cte ( combination, curr ) AS (
SELECT CAST(ic.code AS VARCHAR(MAX)), ic.id
FROM items_code ic
UNION ALL
SELECT CAST( c.combination + ',' + CAST(ic.code AS VARCHAR(10) ) AS VARCHAR(MAX) ), ic.id
FROM item_code ic
INNER JOIN
cte c
ON ( c.curr < ic.id )
)
SELECT combination FROM cte
UPDATE: I have a slightly more complicated schema than what I originally posted, and have built the schema in this fiddle. The idea is the same, it's just that "order" is defined on a different table.
Adding a little more to your recursive cte, expanding the final join conditions, as well as some additional columns:
;with cte as (
select
ic.id
, ic.item_id
, ic.group_id
, g.[order]
, level = 0
, combination = cast(ic.code as varchar(max))
from item_code ic
inner join groups g
on ic.group_id = g.id
union all
select
ic.id
, ic.item_id
, ic.group_id
, g.[order]
, level = c.level + 1
, combination = cast( c.combination + ',' + cast(ic.code as varchar(10) ) as varchar(max) )
from item_code ic
inner join groups g
on ic.group_id = g.id
inner join cte c
on c.id < ic.id
and c.[order] < g.[order]
and c.item_id = ic.item_id
)
select *
from cte
order by item_id, level, combination
rextester demo: http://rextester.com/PJC44281
returns:
+----+---------+----------+-------+-------+-------------------------+
| id | item_id | group_id | order | level | combination |
+----+---------+----------+-------+-------+-------------------------+
| 1 | 99 | 1 | 10 | 0 | code1-1 |
| 2 | 99 | 1 | 10 | 0 | code1-2 |
| 3 | 99 | 2 | 20 | 0 | code2-1 |
| 4 | 99 | 2 | 20 | 0 | code2-2 |
| 5 | 99 | 3 | 30 | 0 | code3-1 |
| 3 | 99 | 2 | 20 | 1 | code1-1,code2-1 |
| 4 | 99 | 2 | 20 | 1 | code1-1,code2-2 |
| 5 | 99 | 3 | 30 | 1 | code1-1,code3-1 |
| 3 | 99 | 2 | 20 | 1 | code1-2,code2-1 |
| 4 | 99 | 2 | 20 | 1 | code1-2,code2-2 |
| 5 | 99 | 3 | 30 | 1 | code1-2,code3-1 |
| 5 | 99 | 3 | 30 | 1 | code2-1,code3-1 |
| 5 | 99 | 3 | 30 | 1 | code2-2,code3-1 |
| 5 | 99 | 3 | 30 | 2 | code1-1,code2-1,code3-1 |
| 5 | 99 | 3 | 30 | 2 | code1-1,code2-2,code3-1 |
| 5 | 99 | 3 | 30 | 2 | code1-2,code2-1,code3-1 |
| 5 | 99 | 3 | 30 | 2 | code1-2,code2-2,code3-1 |
| 6 | 100 | 1 | 10 | 0 | another-code |
+----+---------+----------+-------+-------+-------------------------+

Update a column and refer back it in the same query

I have a table in SQL Server 2014 and need to recursively update a column based on its previous value. For e.g.
---------------------------------------
ID | price | diff_with_prev_price |
---------------------------------------
1 | 29 | 0 |
2 | 25 | 0 |
3 | 20 | 0 |
4 | 35 | 0 |
5 | 40 | 0 |
--------------------------------------|
I want to recursively update third column like below
---------------------------------------
ID | price | diff_with_prev_price |
---------------------------------------
1 | 29 | 0 |
2 | 25 | 25 |
3 | 20 | 5 |
4 | 35 | -30 |
5 | 40 | 10 |
--------------------------------------|
It is the summation of previous value of third column with next value of 'price'.
Can someone please give some hint to do this either using CTE or LEAD/LAG, but without using cursors. I have to update million rows.
You can try this:
SELECT 1 AS ID , 29 AS price, 0 AS diff_with_prev_prive
INTO #tmp
UNION SELECT 2 AS ID , 25 AS price, 0 AS diff_with_prev_prive
UNION SELECT 3 AS ID , 20 AS price, 0 AS diff_with_prev_prive
UNION SELECT 4 AS ID , 35 AS price, 0 AS diff_with_prev_prive
UNION SELECT 5 AS ID , 40 AS price, 0 AS diff_with_prev_prive
WITH cte AS
(
SELECT
ID
, price
, diff_with_prev_prive
, price - ISNULL(LAG(price) OVER (ORDER BY ID),0) AS new_value
FROM #tmp
)
UPDATE t
SET diff_with_prev_prive = t.new_value
FROM cte t
SELECT * FROM #tmp