Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Можно ли переписать запрос без курсора?  [new]
Veligord
Member

Откуда: Москва
Сообщений: 92
Есть вот такая таблица:

CREATE TABLE [dbo].[T_Blank](
	[ID] [bigint] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
	[UserID] [int] NULL,
	[Created] [datetime] NULL,
	[CancelDate] [datetime] NULL
 CONSTRAINT [PK_T_Blank] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]


В ней около 3 миллионов записей. В нее добавили столбец [SetId] [bigint] NULL.

Необходимо заполнить этот столбец (SetId) числами от 1 до n, где n - количество пользователей. Если есть записи с одинаковым, то для этих записей SetId - одинаковый.

Написал такой запрос:

declare @id int
    declare @userId int
    declare @uId int = 0
	declare @setId int = 0
	
	declare  curWorkTable cursor LOCAL fast_forward read_only for
		SELECT ID, UserId from T_Blank
	open curWorkTable
	FETCH NEXT FROM curWorkTable INTO @id, @userId
	WHILE @@FETCH_STATUS = 0
	BEGIN
		if @uId != @userId
			set @setId = @setId + 1
		
		update T_Blank set SetID = @setId
			where ID = @ID
		
		set @uId = @userId
				
		FETCH NEXT FROM curWorkTable INTO @id, @userId
	END
	
	close curWorkTable


Но он на 3 миллионах записей он будет работать ну ооочень долго. Можно ли его переписать без курсора?
20 авг 13, 17:51    [14732272]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
Shakill
Member

Откуда: мск
Сообщений: 1882
Veligord, а в каком порядке должны обрабатываться данные? в курсоре почему-то не видно ORDER BY
20 авг 13, 18:07    [14732364]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
Winnipuh
Member [заблокирован]

Откуда: Київ
Сообщений: 10428
немного сумбурно выглядит... или я не понял...

что вы здесь подсчитываете?

if @uId != @userId
set @setId = @setId + 1
20 авг 13, 18:09    [14732374]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
aleks2
Guest
Veligord
Можно ли его переписать без курсора?


Ну... изучите DENSE_RANK() что ли?
20 авг 13, 18:19    [14732419]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
aleks2
Guest
НО я бы сделал тупо и прямолинейно
declare @t table(UserID [int] primary key clustered, i int identity);

insert @t (UserID)
  select distinct UserID from [dbo].[T_Blank];

update b set SetId = t.i
  from [dbo].[T_Blank] b inner join @t t on b.UserID = t.UserID;
20 авг 13, 18:26    [14732444]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
Veligord
Member

Откуда: Москва
Сообщений: 92
Shakil, Order by ID asc

Winnipuh,

if @uId != @userId
set @setId = @setId + 1

это проверка - если id пользователя изменилось, то SetId нужно увеличить на 1
21 авг 13, 10:17    [14734345]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
Ivan Durak
Member

Откуда: Minsk!!!
Сообщений: 3646
UPDATE T SET SetId = sub.cnt
FROM dbo.T_Blank T
inner join
( 
   select ID, count(UserID) as cnt FROM dbo.T_Blank group by ID 
) sub on sub.ID = T.ID 
21 авг 13, 10:36    [14734459]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
Veligord
Member

Откуда: Москва
Сообщений: 92
Ivan Durak, Спасибо, но это немного не то, что мне нужно. Этот скрипт заполняет SetId количеством вхождений пользователя в таблице. А мне нужно, чтобы было просто перечисление от 1 до n. Но, чтобы для одного пользователя SetId был одинаковый. Да, к тому же у меня этот скрипт почему-то заполняет SetId только единиицами. Хотя многие пользователи повторяются десятки и сотни раз.

UPDATE T SET SetId = sub.cnt
FROM dbo.T_Blank T
inner join
( 
   select ID, count(UserID) as cnt FROM dbo.T_Blank group by ID 
) sub on sub.ID = T.ID 
21 авг 13, 14:06    [14736106]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
Shakill
Member

Откуда: мск
Сообщений: 1882
Veligord, а если записи с одинаковым UserId идут не подряд (order by id), то у них должен быть одинаковый setId или разный?
21 авг 13, 14:18    [14736186]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
Veligord
Member

Откуда: Москва
Сообщений: 92
Одинаковый
21 авг 13, 14:47    [14736465]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
Veligord
Member

Откуда: Москва
Сообщений: 92
Всем спасибо, сделал вот так:

UPDATE T 
SET SetId = sub.setId
FROM dbo.T_Blank as T
inner join
( 
   select ID, Dense_RANK() OVER(ORDER BY CashierId) as setId
	from dbo.T_Blank 
) sub on sub.ID = T.ID 
21 авг 13, 15:03    [14736614]     Ответить | Цитировать Сообщить модератору
 Re: Можно ли переписать запрос без курсора?  [new]
iap
Member

Откуда: Москва
Сообщений: 47049
Veligord
Всем спасибо, сделал вот так:

UPDATE T 
SET SetId = sub.setId
FROM dbo.T_Blank as T
inner join
( 
   select ID, Dense_RANK() OVER(ORDER BY CashierId) as setId
	from dbo.T_Blank 
) sub on sub.ID = T.ID 
Этот запрос можно написать намного короче:
WITH CTE AS(SELECT SetId,NewSetId=DENSE_RANK()OVER(ORDER BY CashierId) FROM dbo.T_Blank)
UPDATE CTE SET SetId=NewSetId;
21 авг 13, 15:27    [14736860]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить