How to auto increment update a column in a SQL Server table - sql-server

How to auto increment update a column in a SQL Server table based on sorting other columns and restart the increment after value changes in other columns.
My table structure and data is like that:
Name Class OldSrNo NewSrNo
----------------------------
aa 1 1 1
bb 1 2 2
aa 1 3 3
bb 2 4 1
cc 2 5 2
dd 2 6 3
aa 2 7 4
I want to update old sr no to look like NewSrNo

Are you asking this,
Declare #t table (Name varchar(50), Class int, OldSrNo int)
insert into #t values
('aa', 1, 1)
,('bb', 1, 2)
,('aa', 1, 3)
,('bb', 2, 4)
,('cc', 2, 5)
,('dd', 2, 6)
,('aa', 2, 7)
select *,
row_number()over(partition by class order by class)NewSrNo
from #t

Related

Update JSON value - MSSQL

In MSSQL I need to update the actualWatchedTime with totalDuration.
Current Table
Id VideoId UserId ProgressJson
1 1 1 {"actualWatchedTime":228,"currentWatchTime":3,"totalDuration":657}
2 2 1 {"actualWatchedTime":328,"currentWatchTime":23,"totalDuration":349}
3 3 1 {"actualWatchedTime":28,"currentWatchTime":2,"totalDuration":576}
4 1 2 {"actualWatchedTime":82,"currentWatchTime":103,"totalDuration":576}
5 2 2 {"actualWatchedTime":280,"currentWatchTime":253,"totalDuration":456}
Expected Table
Id VideoId UserId ProgressJson
1 1 1 {"actualWatchedTime":657,"currentWatchTime":3,"totalDuration":657}
2 2 1 {"actualWatchedTime":349,"currentWatchTime":23,"totalDuration":349}
3 3 1 {"actualWatchedTime":576,"currentWatchTime":2,"totalDuration":576}
4 1 2 {"actualWatchedTime":576,"currentWatchTime":103,"totalDuration":576}
5 2 2 {"actualWatchedTime":456,"currentWatchTime":253,"totalDuration":456}
How do I do that?
declare #t table
(
id int,
ProgressJson nvarchar(500)
);
insert into #t(id, ProgressJson)
values
(1, N'{"actualWatchedTime":228,"currentWatchTime":3,"totalDuration":657}'),
(2, N'{"actualWatchedTime":328,"currentWatchTime":23,"totalDuration":349}'),
(3, N'{"actualWatchedTime":28,"currentWatchTime":2,"totalDuration":576}'),
(4, N'{"actualWatchedTime":82,"currentWatchTime":103,"totalDuration":576}'),
(5, N'{"actualWatchedTime":280,"currentWatchTime":253,"totalDuration":456}');
select *
from #t;
update #t
set ProgressJson = JSON_MODIFY(ProgressJson,'$.actualWatchedTime', cast(json_value(ProgressJson, '$.totalDuration') as int));
select *
from #t;

Rank or merge sequential rows

I have a log file I need to either rank (but treating sequential and equal rows as ties), or merge sequential equal rows (based on specific column). My table looks like below, The Start and Stop are all being sequential (within the same ID window)
ID Start Stop Value
1 0 1 A
1 1 2 A
1 2 3 A
1 3 4 B
1 4 5 B
1 5 6 A
2 3 4 A
I have two approches to get what I need.
Approach 1: Rank (treating sequential rows with equal values in "Value" as ties) and using ID as partition.
This should give the output below. But how do I do the special rank: Treating sequential rows with equal values in "Value" as ties.
Select *,
rank() OVER (partition by id order by start, stop) as Rank,
XXX as SpecialRank
from Table
ID Start Stop Value Rank SpecialRank
1 0 1 A 1 1
1 1 2 A 2 1
1 2 3 A 3 1
1 3 4 B 4 2
1 4 5 B 5 2
1 5 6 A 6 3
2 3 4 A 1 1
Approach 2: Merge sequential rows with equal values in "Value".
This will shall create a table like below.
ID Start Stop Value
1 0 3 A
1 3 5 B
1 5 6 A
2 3 4 A
I don't know if this helps, but I have also a nextValue column that might help in this
ID Start Stop Value NextValue
1 0 1 A A
1 1 2 A A
1 2 3 A B
1 3 4 B B
1 4 5 B A
1 5 6 A A
2 3 4 A ...
Example-table:
CREATE TABLE #Table ( id int, start int, stop int, Value char(1), NextValue char(1));
INSERT INTO #Table values (1,0, 1, 'A', 'A');
INSERT INTO #Table values (1,1, 2, 'A', 'A');
INSERT INTO #Table values (1,2, 3, 'A', 'B');
INSERT INTO #Table values (1,3, 4, 'B', 'B');
INSERT INTO #Table values (1,4, 5, 'B', 'A');
INSERT INTO #Table values (1,5, 6, 'A', 'A');
INSERT INTO #Table values (2,3, 4, 'A', null);
Use a self join to an aggregate subquery from the full set, e.g.
with rankTable (id, value) as
( select 1, 'A' union all select 1, 'A' union all select 1, 'B' union all select 2, 'A')
select t2.* from rankTable t1 join (
select id, value, rank() over (partition by id order by value) as specialRank from
(
select distinct id, value
from rankTable
) t) t2 on t2.id =t1.id and t2.value = t1.value
id value specialRank
1 A 1
1 A 1
1 B 2
2 A 1

SQL Server - recursively calculated column

I need to calculate a column based of a seed row where each row's value uses the "previous" row's values. I feel like this should be a recursive query but I can't quite wrap my head around it.
To illustrate:
BOP EOP IN OUT Wk_Num
--------------------------------------
6 4 10 12 1
? ? 2 6 2
? ? 7 5 3
... ... ... ... ...
So the next row's BOP and EOP columns need to be calculated using the seed row. The IN and OUT values are already present in the table.
BOP = (previous row's EOP)
EOP = (Previous row's EOP) + IN - OUT [where IN and OUT are from the current row)
OUTPUT of this example should look like:
BOP EOP IN OUT Wk_num
-------------------------------------
6 4 10 12 1
4 0 2 6 2
0 2 7 5 3
2 6 4 0 4
... ... ... ... ...
You can use a Recursive CTE for this;
WITH RecursiveCTE AS (
-- Base Case
SELECT
BOP,
EOP,
[IN],
[OUT],
[WK_Num]
FROM [someTable]
WHERE BOP IS NOT NULL
UNION ALL
SELECT
r.EOP AS BOP,
r.EOP + r2.[In] - r2.[Out] AS EOP,
r2.[IN],
r2.[OUT],
r2.[WK_Num]
FROM [someTable] r2
INNER JOIN [RecursiveCTE] r
ON r2.[Wk_Num] = r.[Wk_Num] + 1
)
SELECT * FROM RecursiveCTE
Here is a SQL Fiddle: http://sqlfiddle.com/#!18/e041f/1
You basically define the base case as the first row (by saying the row with BOP != null), then join to each following week with the Wk_Num + 1 join, and reference the previous rows values
You can use SUM OVER like this:
DECLARE #TempTable AS TABLE(T_In INT, T_Out INT, T_WeekNum INT)
INSERT INTO #TempTable VALUES (6, 0, 0)
INSERT INTO #TempTable VALUES (10, 12, 1)
INSERT INTO #TempTable VALUES (2, 6, 2)
INSERT INTO #TempTable VALUES (7, 5, 3)
INSERT INTO #TempTable VALUES (4, 0, 4)
SELECT
SUM(T_In - T_Out) OVER(ORDER BY T_WeekNum ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) - T_In + T_Out AS T_Bop,
SUM(T_In - T_Out) OVER(ORDER BY T_WeekNum ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS T_Eop,
T_In,
T_Out,
T_WeekNum
FROM #TempTable
The calculation is the same for BOP and EOP but the values from the current row are subtracted from the BOP column to get the value from the last row.

Separate a group of values in to A or B (1 or 2) SQL

Note: I have already asked a similar question but had omitted a key part in the fact that a tool has many components.
I have a list of multiple tools and their components that all have a model number. I want to group every second tool based on the model it belongs to.
The derivedColumn is the query I want to return
declare #t table (Model int, toolID INT ,Component INT,DerivedColumn int);
insert into #t values (1,1,1,1),(1,1,2,1),(1,1,3,1),(1,2,1,2),(1,2,2,2),(1,2,3,2),(1,3,1,1),(1,3,2,1),(1,3,3,1),(1,4,1,2),(1,4,2,2),(1,4,3,2),(1,5,1,1),(1,5,2,1),(1,5,3,1),(2,1,1,1),(2,1,2,1),(2,2,1,2),(2,2,2,2),(2,3,1,1),(2,3,2,1)
SELECT * FROM #t
Model toolID Component DerivedColumn
1 1 1 1
1 1 2 1
1 1 3 1
1 2 1 2
1 2 2 2
1 2 3 2
1 3 1 1
1 3 2 1
1 3 3 1
1 4 1 2
1 4 2 2
1 4 3 2
1 5 1 1
1 5 2 1
1 5 3 1
2 1 1 1
2 1 2 1
2 2 1 2
2 2 2 2
2 3 1 1
2 3 2 1
Every second tool belonging to a model should have an alternative group number.
I believe I have to use a windows function but haven't been able to solve.
You could use dense_rank() and mod function %2 to calculate
DECLARE #SampleData AS TABLE
(
Model int,
ToolId int,
Component int
)
INSERT INTO #SampleData
(
Model, ToolId, Component
)
VALUES
(1, 1, 1),(1, 1, 2),(1, 1, 3),(1, 2, 1),
(1, 2, 2),(1, 2, 3),(1, 3, 1),(1, 3, 2),
(1, 3, 3),(1, 4, 1),(1, 4, 2),(1, 4, 3),
(1, 5, 1),(1, 5, 2),(1, 5, 3),(2, 1, 1),
(2, 1, 2),(2, 2, 1),(2, 2, 2),(2, 3, 1),
(2, 3, 2)
SELECT *,
CASE (dense_rank() OVER(PARTITION BY sd.Model ORDER BY sd.ToolId) + 1) % 2
WHEN 1 THEN 2
WHEN 0 THEN 1
END as DerivedColumn
FROM #SampleData sd
ORDER BY sd.Model, sd.ToolId
Demo link: http://rextester.com/LIQL79881
Hope it may helps you
DECLARE #T TABLE (Model INT, toolID INT ,Component INT,DerivedColumn INT);
INSERT INTO #T VALUES (1,1,1,1),(1,1,2,1),(1,1,3,1),(1,2,1,2),(1,2,2,2),(1,2,3,2),(1,3,1,1),(1,3,2,1),(1,3,3,1),(1,4,1,2),(1,4,2,2),(1,4,3,2),(1,5,1,1),(1,5,2,1),(1,5,3,1),(2,1,1,1),(2,1,2,1),(2,2,1,2),(2,2,2,2),(2,3,1,1),(2,3,2,1)
SELECT Model
,toolID
,ROW_NUMBER()Over(Partition by toolID order by Model) AS AlternativetoolID
,Component
,DerivedColumn
from #t;

How we can get two rows before and after for a given id in a table?

I have a table with 10 rows
id values
1 a
2 b
3 c
4 d
5 e
6 f
7 g
8 h
9 i
10 j
I want to get two rows before and two rows after for #id = 5.
How can get?
Edit This should work as expected (hopefully):
select id, value
from [table]
where id-#id >= -2
AND id-#id <= 2
AND id-#id <> 0
Here's the running sql: http://sqlfiddle.com/#!6/ca4e5/3/0
One possible solution:
select *
from table
where id in (3, 4, 6, 7)
If you are using a int variable #id, you can do it like this:
select *
from table
where id in (#id-2, #id-1, #id+1, #id+2)
To select the previous two:
select top 2 *
from tablename
where id < #id
order by id desc
To select the next two:
select top 2 *
from tablename
where id > #id
order by id asc

Resources