Cursor in Mysql not working in Mysql 5.57
I converted SQL query into MySQL query, SQL query give me records, but in Mysql query is doesn't provide any records and neither give any error
//Following is my SQL query
USE [Trackdb]
GO
/****** Object: StoredProcedure [dbo].[GetRecords] Script Date: 06-11-2019 09:48:05 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetRecords]
AS
BEGIN
DECLARE #Date VARCHAR(15)
create table #TempHotel
(
CatID Varchar(50),
Cnt INT,
Date Date
)
create table #TempRestaurant
(
CatID Varchar(50),
Cnt INT,
Date Date
)
DECLARE Track_CURSOR CURSOR
LOCAL FORWARD_ONLY FOR
SELECT Distinct(Convert(date,ms_date)) FROM tbltrackingrtt WHERE ms_date > '2017-11-01' AND heirarchy LIKE '%*145*%' AND category <> 0 AND category <> 145
OPEN Track_CURSOR
FETCH NEXT FROM Track_CURSOR INTO #Date
WHILE ##FETCH_STATUS = 0
BEGIN
--PRINT 'EMP_ID: ' + #Date --+ ' EMP_NAME '+#EMP_NAME +' EMP_SALARY ' +CONVERT(NVARCHAR(MAX),#EMP_SALARY) + ' EMP_CITY ' +#EMP_CITY
INSERT INTO #TempHotel
SELECT TOP 100 Category AS CatID, Count(id) Cnt, convert(Date,ms_date) Date FROM tbltrackingrtt
WHERE heirarchy LIKE '%*145*%' AND category <> 0 AND category <> 145 AND CONVERT(DATE,ms_date) = #Date
GROUP BY Category, convert(Date,ms_date)
ORDER BY convert(Date,ms_date) ASC, Count(id) DESC
INSERT INTO #TempRestaurant
SELECT TOP 100 Category AS CatID, Count(id) Cnt, convert(Date,ms_date) Date FROM tbltrackingrtt
WHERE heirarchy LIKE '%*169*%' AND category <> 0 AND category <> 169 AND CONVERT(DATE,ms_date) = #Date
GROUP BY Category, convert(Date,ms_date)
ORDER BY convert(Date,ms_date) ASC, Count(id) DESC
FETCH NEXT FROM Track_CURSOR INTO #Date
END
SELECT * FROM #TempHotel
SELECT * FROM #TempRestaurant
CLOSE Track_CURSOR
DEALLOCATE Track_CURSOR
DROP table #TempHotel
DROP table #TempRestaurant
END
// Following is my Mysql query
CREATE DEFINER=`root`#`localhost` PROCEDURE `GetRecords`()
BEGIN
DECLARE NOT_FOUND INT DEFAULT 0;
DECLARE v_Date VARCHAR(15);
DECLARE Track_CURSOR
CURSOR FOR
SELECT Distinct CAST(ms_date as Date) FROM tbltrackingrtt WHERE ms_date > '2017-11-01' AND heirarchy LIKE '%*145*%' AND category <> 0 AND category <> 145;
create temporary table TempHotel
(
CatID Varchar(50),
Cnt INT,
Date Date
);
create temporary table TempRestaurant
(
CatID Varchar(50),
Cnt INT,
Date Date
);
OPEN Track_CURSOR;
FETCH Track_CURSOR INTO v_Date;
WHILE NOT_FOUND = 0
DO
-- PRINT 'EMP_ID: ' + #Date --+ ' EMP_NAME '+#EMP_NAME +' EMP_SALARY ' +CONVERT(NVARCHAR(MAX),#EMP_SALARY) + ' EMP_CITY ' +#EMP_CITY
INSERT INTO TempHotel
SELECT Category AS CatID, Count(id) Cnt, CAST(ms_date as Date) as Date FROM tbltrackingrtt
WHERE heirarchy LIKE '%*145*%' AND category <> 0 AND category <> 145 AND CAST(ms_date as Date) = v_Date
GROUP BY Category, CAST(ms_date as Date)
ORDER BY CAST(ms_date as Date) ASC, Count(id) DESC LIMIT 100;
select TempHotel;
INSERT INTO TempRestaurant
SELECT Category AS CatID, Count(id) Cnt, CAST(ms_date as Date) as Date FROM tbltrackingrtt
WHERE heirarchy LIKE '%*169*%' AND category <> 0 AND category <> 169 AND CAST(ms_date as Date) = v_Date
GROUP BY Category, CAST(ms_date as Date)
ORDER BY CAST(ms_date as Date) ASC, Count(id) DESC LIMIT 100;
FETCH Track_CURSOR INTO v_Date;
END WHILE;
SELECT * FROM TempHotel;
SELECT * FROM TempRestaurant
CLOSE;
DROP table TempHotel;
DROP table TempRestaurant;
END
Anyone help me on this, I don't what I am doing wrong here, is there is any problem in MySQL cursor
Apart from the syntax error pointed out by #solarflare the only thing that appears to be wrong with this code is the lack of a handler you should review https://dev.mysql.com/doc/refman/8.0/en/cursors.html and https://dev.mysql.com/doc/refman/5.7/en/handler.html (which you should know about for error handling in mysql)
drop procedure if exists p;
drop temporary table if exists temphotel,temprestaurant;
drop table if exists tbltrackingrtt;
create table tbltrackingrtt
(id int auto_increment primary key,ms_date date,heirarchy varchar(20),category int);
insert into tbltrackingrtt (ms_date,heirarchy,category) values
('2017-11-02','*145*',10), ('2017-11-02','*145*',10),
('2017-11-02','*169*',10), ('2017-11-02','*145*',10);
delimiter $$
CREATE PROCEDURE p()
BEGIN
DECLARE NOT_FOUND INT DEFAULT 0;
DECLARE v_Date VARCHAR(15);
DECLARE Track_CURSOR
CURSOR FOR
SELECT Distinct CAST(ms_date as Date)
FROM tbltrackingrtt
WHERE ms_date > '2017-11-01' AND heirarchy LIKE '%*145*%' AND category <> 0 AND category <> 145;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET not_found = TRUE;
create temporary table TempHotel
(
CatID Varchar(50),
Cnt INT,
Date Date
);
create temporary table TempRestaurant
(
CatID Varchar(50),
Cnt INT,
Date Date
);
OPEN Track_CURSOR;
FETCH Track_CURSOR INTO v_Date;
WHILE NOT_FOUND = 0 DO
-- PRINT 'EMP_ID: ' + #Date --+ ' EMP_NAME '+#EMP_NAME +' EMP_SALARY ' +CONVERT(NVARCHAR(MAX),#EMP_SALARY) + ' EMP_CITY ' +#EMP_CITY
INSERT INTO TempHotel
SELECT Category AS CatID, Count(id) Cnt, CAST(ms_date as Date) as Date
FROM tbltrackingrtt
WHERE heirarchy LIKE '%*145*%' AND category <> 0 AND category <> 145 AND CAST(ms_date as Date) = v_Date
GROUP BY Category, CAST(ms_date as Date)
ORDER BY CAST(ms_date as Date) ASC, Count(id) DESC LIMIT 100;
select * from TempHotel;
INSERT INTO TempRestaurant
SELECT Category AS CatID, Count(id) Cnt, CAST(ms_date as Date) as Date
FROM tbltrackingrtt
WHERE heirarchy LIKE '%*169*%' AND category <> 0 AND category <> 169 AND CAST(ms_date as Date) = v_Date
GROUP BY Category, CAST(ms_date as Date)
ORDER BY CAST(ms_date as Date) ASC, Count(id) DESC LIMIT 100;
FETCH Track_CURSOR INTO v_Date;
END WHILE;
SELECT * FROM TempHotel;
SELECT * FROM TempRestaurant
CLOSE;
DROP table TempHotel;
DROP table TempRestaurant;
END $$
delimiter ;
call p();
+-------+------+------------+
| CatID | Cnt | Date |
+-------+------+------------+
| 10 | 3 | 2017-11-02 |
+-------+------+------------+
1 row in set (0.27 sec)
+-------+------+------------+
| CatID | Cnt | Date |
+-------+------+------------+
| 10 | 3 | 2017-11-02 |
+-------+------+------------+
1 row in set (0.29 sec)
+-------+------+------------+
| CatID | Cnt | Date |
+-------+------+------------+
| 10 | 1 | 2017-11-02 |
+-------+------+------------+
1 row in set (0.30 sec)
How do I accomplish my goal without using temp table or variable?
Table:
ID ModelNum Qty
123 ABC 4
123 DEF 4
Expected Result:
ID Models Qty
123 ABC | DEF 4
Thanks in advance!
DECLARE #T TABLE (ID INT,ModelNum CHAR(3),Qty INT)
INSERT INTO #T
VALUES
(123,'ABC',4),
(123,'DEF',4),
(123,'GLK',4)
SELECT DISTINCT ID, STUFF(C.List, 1, 2, '') Models, Qty
FROM #T t
CROSS APPLY (
SELECT '| ' + ModelNum
FROM #T
WHERE ID = t.ID
FOR XML PATH('')
)C(List)
Result Set
ID Models Qty
123 ABC| DEF| GLK 4
Hi how about this Query below:
I have did the same example with some different logic and different attribute.
I can get the expected OP, please response if you have any suggestions for me on btechit#hotmail.com.
Declare:
#ConcatTable table (Ename varchar(30), Empno int)
Insert into #ConcatTable values ('Steve', 100),('mathew', 100),('jon', 101),('tom', 101)
--select * from #ConcatTable
--select ROW_NUMBER()over(order by Empno)Row2,* from
--(select distinct Empno from #ConcatTable)C
declare #p varchar(100) = ''
select #p = #p+ ' '+Ename from (
select DENSE_RANK()over(order by Empno)as dens, * from #ConcatTable )A
where A.dens = 1
declare #q varchar(100) = ''
select #q = #q+ ' '+Ename from (
select DENSE_RANK()over(order by Empno)as dens, * from #ConcatTable )A
where A.dens = 2
--SELECT #p
--SELECT #q
declare #M table (Name varchar(30))
insert into #M
select * from(
select #p as v
union all
select #q as vv
)G
--SELECT ROW_NUMBER()over (order by Name desc)Rown1,* from #M
SELECT A.Name,CC.Empno FROM(
SELECT ROW_NUMBER()over (order by Name desc)Rown1,* FROM #M)A
inner join
(select ROW_NUMBER()over(order by Empno)Row2,* from
(select distinct Empno from #ConcatTable)C
)CC
on A.Rown1 = CC.Row2
I have table :
id | name
1 | a,b,c
2 | b
i want output like this :
id | name
1 | a
1 | b
1 | c
2 | b
If you can create a numbers table, that contains numbers from 1 to the maximum fields to split, you could use a solution like this:
select
tablename.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.name, ',', numbers.n), ',', -1) name
from
numbers inner join tablename
on CHAR_LENGTH(tablename.name)
-CHAR_LENGTH(REPLACE(tablename.name, ',', ''))>=numbers.n-1
order by
id, n
Please see fiddle here.
If you cannot create a table, then a solution can be this:
select
tablename.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.name, ',', numbers.n), ',', -1) name
from
(select 1 n union all
select 2 union all select 3 union all
select 4 union all select 5) numbers INNER JOIN tablename
on CHAR_LENGTH(tablename.name)
-CHAR_LENGTH(REPLACE(tablename.name, ',', ''))>=numbers.n-1
order by
id, n
an example fiddle is here.
If the name column were a JSON array (like '["a","b","c"]'), then you could extract/unpack it with JSON_TABLE() (available since MySQL 8.0.4):
select t.id, j.name
from mytable t
join json_table(
t.name,
'$[*]' columns (name varchar(50) path '$')
) j;
Result:
| id | name |
| --- | ---- |
| 1 | a |
| 1 | b |
| 1 | c |
| 2 | b |
View on DB Fiddle
If you store the values in a simple CSV format, then you would first need to convert it to JSON:
select t.id, j.name
from mytable t
join json_table(
replace(json_array(t.name), ',', '","'),
'$[*]' columns (name varchar(50) path '$')
) j
Result:
| id | name |
| --- | ---- |
| 1 | a |
| 1 | b |
| 1 | c |
| 2 | b |
View on DB Fiddle
I have take the reference from here with changed column name.
DELIMITER $$
CREATE FUNCTION strSplit(x VARCHAR(65000), delim VARCHAR(12), pos INTEGER)
RETURNS VARCHAR(65000)
BEGIN
DECLARE output VARCHAR(65000);
SET output = REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos)
, LENGTH(SUBSTRING_INDEX(x, delim, pos - 1)) + 1)
, delim
, '');
IF output = '' THEN SET output = null; END IF;
RETURN output;
END $$
CREATE PROCEDURE BadTableToGoodTable()
BEGIN
DECLARE i INTEGER;
SET i = 1;
REPEAT
INSERT INTO GoodTable (id, name)
SELECT id, strSplit(name, ',', i) FROM BadTable
WHERE strSplit(name, ',', i) IS NOT NULL;
SET i = i + 1;
UNTIL ROW_COUNT() = 0
END REPEAT;
END $$
DELIMITER ;
Here is my attempt:
The first select presents the csv field to the split.
Using recursive CTE, we can create a list of numbers that are limited to the number of terms in the csv field.
The number of terms is just the difference in the length of the csv field and itself with all the delimiters removed.
Then joining with this numbers, substring_index extracts that term.
with recursive
T as ( select 'a,b,c,d,e,f' as items),
N as ( select 1 as n union select n + 1 from N, T
where n <= length(items) - length(replace(items, ',', '')))
select distinct substring_index(substring_index(items, ',', n), ',', -1)
group_name from N, T
My variant: stored procedure that takes table name, field names and delimiter as arguments. Inspired by post http://www.marcogoncalves.com/2011/03/mysql-split-column-string-into-rows/
delimiter $$
DROP PROCEDURE IF EXISTS split_value_into_multiple_rows $$
CREATE PROCEDURE split_value_into_multiple_rows(tablename VARCHAR(20),
id_column VARCHAR(20), value_column VARCHAR(20), delim CHAR(1))
BEGIN
DECLARE id INT DEFAULT 0;
DECLARE value VARCHAR(255);
DECLARE occurrences INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE splitted_value VARCHAR(255);
DECLARE done INT DEFAULT 0;
DECLARE cur CURSOR FOR SELECT tmp_table1.id, tmp_table1.value FROM
tmp_table1 WHERE tmp_table1.value IS NOT NULL AND tmp_table1.value != '';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SET #expr = CONCAT('CREATE TEMPORARY TABLE tmp_table1 (id INT NOT NULL, value VARCHAR(255)) ENGINE=Memory SELECT ',
id_column,' id, ', value_column,' value FROM ',tablename);
PREPARE stmt FROM #expr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TEMPORARY TABLE IF EXISTS tmp_table2;
CREATE TEMPORARY TABLE tmp_table2 (id INT NOT NULL, value VARCHAR(255) NOT NULL) ENGINE=Memory;
OPEN cur;
read_loop: LOOP
FETCH cur INTO id, value;
IF done THEN
LEAVE read_loop;
END IF;
SET occurrences = (SELECT CHAR_LENGTH(value) -
CHAR_LENGTH(REPLACE(value, delim, '')) + 1);
SET i=1;
WHILE i <= occurrences DO
SET splitted_value = (SELECT TRIM(SUBSTRING_INDEX(
SUBSTRING_INDEX(value, delim, i), delim, -1)));
INSERT INTO tmp_table2 VALUES (id, splitted_value);
SET i = i + 1;
END WHILE;
END LOOP;
SELECT * FROM tmp_table2;
CLOSE cur;
DROP TEMPORARY TABLE tmp_table1;
END; $$
delimiter ;
Usage example (normalization):
CALL split_value_into_multiple_rows('my_contacts', 'contact_id', 'interests', ',');
CREATE TABLE interests (
interest_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
interest VARCHAR(30) NOT NULL
) SELECT DISTINCT value interest FROM tmp_table2;
CREATE TABLE contact_interest (
contact_id INT NOT NULL,
interest_id INT NOT NULL,
CONSTRAINT fk_contact_interest_my_contacts_contact_id FOREIGN KEY (contact_id) REFERENCES my_contacts (contact_id),
CONSTRAINT fk_contact_interest_interests_interest_id FOREIGN KEY (interest_id) REFERENCES interests (interest_id)
) SELECT my_contacts.contact_id, interests.interest_id
FROM my_contacts, tmp_table2, interests
WHERE my_contacts.contact_id = tmp_table2.id AND interests.interest = tmp_table2.value;
Because you have to keep adding "select number union all" in the example above which can be a issue if you need a large number of splits.
select
tablename.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.name, ',', numbers.n), ',', -1) name
from
(select 1 n union all
select 2 union all select 3 union all
select 4 union all select 5) numbers INNER JOIN tablename
on CHAR_LENGTH(tablename.name)
-CHAR_LENGTH(REPLACE(tablename.name, ',', ''))>=numbers.n-1
order by
id, n
I decided a better way was this which only adds a number row for each digit. Example below is good for 1-1000 add another row makes it good for 1-10000 and so on.
select
tablename.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.name, ',', numbers.n), ',', -1) name
from(SELECT #row := #row + 1 AS n FROM
(select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as t,
(select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as t2,
(select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as t3,
(SELECT #row:=0) as numbers)as numbers INNER JOIN tablename
on CHAR_LENGTH(tablename.name)
-CHAR_LENGTH(REPLACE(tablename.name, ',', ''))>=numbers.n-1
order by
id, n
CREATE PROCEDURE `getVal`()
BEGIN
declare r_len integer;
declare r_id integer;
declare r_val varchar(20);
declare i integer;
DECLARE found_row int(10);
DECLARE row CURSOR FOR select length(replace(val,"|","")),id,val from split;
create table x(id int,name varchar(20));
open row;
select FOUND_ROWS() into found_row ;
read_loop: LOOP
IF found_row = 0 THEN
LEAVE read_loop;
END IF;
set i = 1;
FETCH row INTO r_len,r_id,r_val;
label1: LOOP
IF i <= r_len THEN
insert into x values( r_id,SUBSTRING(replace(r_val,"|",""),i,1));
SET i = i + 1;
ITERATE label1;
END IF;
LEAVE label1;
END LOOP label1;
set found_row = found_row - 1;
END LOOP;
close row;
select * from x;
drop table x;
END
The original question was for MySQL and SQL in general. The example below is for the new versions of MySQL. Unfortunately, a generic query that would work on any SQL server is not possible. Some servers do no support CTE, others do not have substring_index, yet others have built-in functions for splitting a string into multiple rows.
--- the answer follows ---
Recursive queries are convenient when the server does not provide built-in functionality. They can also be the bottleneck.
The following query was written and tested on MySQL version 8.0.16. It will not work on version 5.7-. The old versions do not support Common Table Expression (CTE) and thus recursive queries.
with recursive
input as (
select 1 as id, 'a,b,c' as names
union
select 2, 'b'
),
recurs as (
select id, 1 as pos, names as remain, substring_index( names, ',', 1 ) as name
from input
union all
select id, pos + 1, substring( remain, char_length( name ) + 2 ),
substring_index( substring( remain, char_length( name ) + 2 ), ',', 1 )
from recurs
where char_length( remain ) > char_length( name )
)
select id, name
from recurs
order by id, pos;
Here is another trick. The number 20 is the maximum number of values in comma separated list.
We use single query, no procedures.
If tbl has more rows than the maximum number of values in single comma separated list you may remove 'inner join tbl a inner join tbl c' part from query. I added this because there are only 2 rows.
CREATE TABLE tbl(id int NOT NULL,name varchar(50),PRIMARY KEY (`id`));
insert into tbl values(1, 'a,b,c'), (2, 'd');
select id ,SUBSTRING_INDEX(SUBSTRING_INDEX(name, ',', k.n), ',', -1) as name
from tbl
INNER JOIN (
SELECT *
FROM (
SELECT #n:=#n+1 AS n
FROM tbl inner join tbl a inner join tbl c
INNER JOIN (SELECT #n:=0) AS _a
) AS _a WHERE _a.n <= 20
)AS k ON k.n <= LENGTH(name) - LENGTH(replace(name, ',','')) + 1
order by id
This is a trick to extract nth value in comma separated list:
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ',', k.n), ',', -1)
Here is my solution
-- Create the maximum number of words we want to pick (indexes in n)
with recursive n(i) as (
select
1 i
union all
select i+1 from n where i < 1000
)
select distinct
s.id,
s.oaddress,
-- n.i,
-- use the index to pick the nth word, the last words will always repeat. Remove the duplicates with distinct
if(instr(reverse(trim(substring_index(s.oaddress,' ',n.i))),' ') > 0,
reverse(substr(reverse(trim(substring_index(s.oaddress,' ',n.i))),1,
instr(reverse(trim(substring_index(s.oaddress,' ',n.i))),' '))),
trim(substring_index(s.oaddress,' ',n.i))) oth
from
app_schools s,
n
Best Practice.
Result:
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX('ab,bc,cd',',',help_id+1),',',-1) AS oid
FROM
(
SELECT #xi:=#xi+1 as help_id from
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc2,
(SELECT #xi:=-1) xc0
) a
WHERE
help_id < LENGTH('ab,bc,cd')-LENGTH(REPLACE('ab,bc,cd',',',''))+1
First, create a numbers table:
SELECT #xi:=#xi+1 as help_id from
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc2,
(SELECT #xi:=-1) xc0;
| help_id |
| --- |
| 0 |
| 1 |
| 2 |
| 3 |
| ... |
| 24 |
Second, just split the str:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('ab,bc,cd',',',help_id+1),',',-1) AS oid
FROM
numbers_table
WHERE
help_id < LENGTH('ab,bc,cd')-LENGTH(REPLACE('ab,bc,cd',',',''))+1
| oid |
| --- |
| ab |
| bc |
| cd |
SELECT id, unnest(string_to_array(name, ',')) AS names
FROM datatable
Hope this helps :D
I have a table which has columns UserID,DIFFTIME. when I select these columns from the table, I also want to have a derived column which is : If the DiffTime is > 20 I want to increment the count per user id.
For example if the table has:
User ID DIFF TIME
1 0
1 5
1 10
2 0
2 21
2 5
I want a result set that is something like this:
User ID DIFF TIME SESSION NUMBER
1 0 1
1 5 1
1 10 1
2 0 1
2 21 2
2 5 2
How do I accomplish this.
Ideas and suggestions are much appreciated!
Use this statement:
select t1.User_Id, t1.Diff_Time,
isnull(count(t2.User_Id), 0) + 1 as Session_Number
from #table t1
left join #table t2
on t1.User_Id = t2.User_Id
and t1.eventTime >= t2.eventTime
and t2.Diff_Time > 20
group by t1.User_Id, t1.Diff_Time, t1.eventTime
order by t1.User_Id, t1.eventTime
(replace #table with your actual table name)
Note: I assume that the fifth row of your table has the value 21 in the Diff_Time column, and there's a typo in the question, as #AaronBertrand pointed out in the comments
create table #t
(
id int,
Diff int,
SessionNumber int
)
insert into #t(id, diff)values(1, 0)
insert into #t(id, diff)values(1, 5)
insert into #t(id, diff)values(1, 10)
insert into #t(id, diff)values(2, 0)
insert into #t(id, diff)values(2, 21)
insert into #t(id, diff)values(2, 5)
Select ROW_NUMBER() over(order by Id) as RowID, * into #Temp1 from #t
Declare #diff int
Declare #RowId int
Declare #Previous int
Declare #NewValue int
DECLARE #Cur CURSOR SET #Cur = CURSOR FOR select RowId, diff from #Temp1
OPEN #Cur
FETCH NEXT FROM #Cur INTO #RowId, #diff
WHILE ##FETCH_STATUS = 0
BEGIN
if(#RowId = 1)
Begin
Update #Temp1 Set SessionNumber = 1 Where rowid = 1
Set #Previous = #Diff
Set #NewValue = 1
End
Else
Begin
if(#Diff - #Previous > 20)
Begin
Set #Previous = #Diff
Set #NewValue = #NewValue + 1
Update #Temp1 Set SessionNumber = #NewValue Where rowid = #RowId
End
else
Update #Temp1 Set SessionNumber = #NewValue Where rowid = #RowId
End
FETCH NEXT FROM #Cur INTO #RowId, #diff
END
CLOSE #Cur
DEALLOCATE #Cur
select * from #temp1
drop table #t
drop table #temp1