Хотя цикл с несколькими условиями в T-SQL. Sql t цикл


sql - Цикл функций T-SQL

Здесь моя реализация с тестовыми таблицами и данными. При необходимости вам придется поменять место. ПРИМЕЧАНИЕ. Я принимаю lateiff + 1 в течение нескольких дней в тюрьме, поэтому, если вы зайдете в понедельник и уйдете во вторник, это будет считаться двумя днями. если вы хотите, чтобы он считался одним днем, удалите "+ 1",

create table PrisonRegistry ( id int not null identity(1,1) primary key , PersonId int not null , ValueTypeId int not null , Value date ) -- ValueTypeIDs: 1 = start prison date, 2 = end prison date insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 1, 1, '2012-03-28' ) insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 1, 1, '2012-10-12' ) insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 1, 2, '2012-03-29' ) insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 2, 1, '2012-01-15' ) insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 2, 2, '2012-02-15' ) insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 2, 1, '2012-04-01' ) insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 2, 2, '2012-04-05' ) insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 2, 1, '2012-09-03' ) insert PrisonRegistry( PersonId, ValueTypeId, Value ) values ( 2, 2, '2012-12-1' ) go create function dbo.NumDaysInPrison( @personId int , @year int ) returns int as begin declare @retVal int set @retVal = 0 declare @valueTypeId int declare @value date declare @startDate date declare @noDates bit set @noDates = 1 set @startDate = DATEFROMPARTS( @year, 1, 1 ) declare prisonCursor cursor for select pr.ValueTypeId , pr.Value from PrisonRegistry pr where DATEPART( yyyy, pr.Value ) = @year and pr.ValueTypeId in (1,2) and PersonId = @personId order by pr.Value open prisonCursor fetch next from prisonCursor into @valueTypeId, @value while @@FETCH_STATUS = 0 begin set @noDates = 0 -- if end date, add date diff to retVal if 2 = @valueTypeId begin --if @startDate is null --begin -- -- error: two end dates in a row -- -- handle --end set @retVal = @retVal + DATEDIFF( dd, @startDate, @value ) + 1 set @startDate = null end else if 1 = @valueTypeId begin set @startDate = @value end fetch next from prisonCursor into @valueTypeId, @value end close prisonCursor deallocate prisonCursor if @startDate is not null and 0 = @noDates begin set @retVal = @retVal + DATEDIFF( dd, @startDate, DATEFROMPARTS( @year, 12, 31 ) ) + 1 end return @retVal end go select dbo.NumDaysInPrison( 1, 2012 ) select dbo.NumDaysInPrison( 2, 2012 ) select dbo.NumDaysInPrison( 2, 2011 )

qaru.site

Хотя цикл с несколькими условиями в T-SQL MS SQL Server

Позвольте мне начать с того, что я знаю, что знаю, что эти циклы ужасны, и вы не должны использовать их в Transact SQL. Но для некоторых целей (эти цели неактуальны, поэтому не спрашивайте меня «что вы пытаетесь сделать !?»), вам просто нужно. Я не хочу, но я должен.

Так или иначе. Есть ли способ, чтобы цикл while в T-SQL заканчивался на сложном условном выражении? например, в C # я бы сказал только (i> -10 && i <10), потому что я хочу, чтобы цикл завершился, когда значение дозорного устройства находится между -10 и 10, но я просто … не могу понять как это сделать.

Это, наверное, мучительно просто … или .. невозможно. Пожалуйста, порекомендуйте.

Прямо сейчас, я только что получил

WHILE @N <> 0 BEGIN --code and such here END
Solutions Collecting From Web of "Хотя цикл с несколькими условиями в T-SQL"

Вы должны посмотреть заявление WHILE:

WHILE Boolean_expression { sql_statement | statement_block | BREAK | CONTINUE }

Прежде всего вы можете использовать сложное Boolean_expression, как сказал Дэн:

WHILE @N > -1 AND @N <10 BEGIN END

Если вы хотите добавить дополнительную гибкость в свой код, вы можете использовать IF с BREAK, что-то вроде этого:

WHILE @N > -1 AND @N <10 BEGIN -- code IF (SELECT MAX(ListPrice) FROM Production.Product) > $500 BREAK END -- code END

выйти из цикла или использовать CONTINUE, чтобы пропустить один цикл.

Я чувствую себя полным идиотом. И я уверен, что я тоже выгляжу.

Я пробовал все это, пытаясь заставить условие работать. Я просто не мог понять, почему он не работает.

Это просто ударило меня. Я менял код во время его отладки, и он не выполнял мои изменения.

Я довольно смущен. В конце концов, я делал это правильно. Я просто … делал это неправильно.

sqlserver.bilee.com

Почему так сложно делать цикл в T-SQL MS SQL Server

Хорошо, я знаю, что это можно сделать, я делаю это довольно часто, но почему так сложно делать цикл в T-SQL? Я могу придумать массу причин, по которым я хотел бы проанализировать набор результатов запроса и сделать то, что просто невозможно сделать без цикла, но код для настройки и выполнения моего цикла -> 20 строк.

Я уверен, что у других есть похожие мнения, так почему мы все еще без простого способа выполнить цикл?

В стороне: мы наконец получили UPSERT (aka MERGE) в SQL2008, поэтому, возможно, вся надежда не потеряна.

SQL – это основанный на наборах декларативный язык ; а не процедурный или императивный язык . T-SQL пытается обойти эти два, но он по-прежнему построен на основе основанной на принципе парадигмы.

Я могу придумать массу причин, по которым я хотел бы проанализировать набор результатов запроса и сделать то, что просто невозможно сделать без цикла

И для подавляющего большинства из них я могу либо показать вам, как это сделать в режиме набора, либо объяснить, почему это должно быть сделано в коде клиента, а не в базе данных. Нужно делать цикл в sql, редко бывает редко.

T-SQL не является обязательным языком. Его цель – декларативная. Его декларативный характер позволяет оптомизатору разрезать различные задачи и запустить их в parrallel и другими способами делать вещи в порядке, который наиболее эффективен.

Поскольку SQL – это язык, основанный на наборе. Сила sql заключается в нахождении меньшей группы в большей группе данных, основанной на конкретных характеристиках. Чтобы справиться с этой задачей, цикл в основном не нужен. Очевидно, что это было добавлено для удобства обработки некоторых ситуаций, но предполагаемое использование языка делает эту функцию неактуальной.

почти все можно сделать на основе набора, попробуйте использовать таблицу чисел

почему 20 строк? Это все, что вам нужно

select *,identity(int, 1,1) as Someid into #temp from sysobjects declare @id int, @MaxId int select @id = 1,@MaxId = max(Someid) from #temp while @id < @MaxId begin -- do your stuff here print @id set @id =@id + 1 end

это зависит от того, что вы хотите сделать в цикле. использование цикла while не сложно:

declare @i int set @i = 20 while @i>0 begin ... do some stuff set @i = @i-1 end

он становится громоздким при использовании курсоров, чего следует избегать в любом случае.

Вы можете попробовать использовать определенные пользователем функции, чтобы выполнять большую часть работы, вместо того, чтобы использовать подход на основе цикла. Это сохранит намерение SQL-языка, который установлен на основе.

SQL – это система на основе SET, а не процедурная (loop). Вообще его считают неправильной практикой использовать циклы в SQL, потому что они плохо работают по сравнению с их эквивалентами на основе набора.

WHILE является наиболее распространенной петлевой структурой, КУРСОРЫ также могут использоваться, но имеют свои собственные проблемы (забывая освободить / закрыть)

… пример WHILE (вам может и не понадобиться, но другие могут)

DECLARE @iterator INT SET @iterator = 0 WHILE @iterator < 20 BEGIN SELECT * FROM table WHERE rowKey = @iterator /*do stuff*/ @iterator = @iterator + 1 END

Реальный вопрос: «Что вы пытаетесь сделать, просто не может быть сделано на основе набора?»

Я не эксперт в БД, но я считаю, что атомная природа транзакций базы данных затрудняет достижение циклов, поскольку транзакция будет полной или вообще не должна возникать. Поддержание состояния может быть надоедливым!

Статья Википедии о атомной

sqlserver.bilee.com

tsql - Бесконечный цикл в курсе T-SQL

Ниже приведен код для курсора T-SQL. Он отлично работает в первой итерации, однако после этого застревает в бесконечном цикле между оператором FETCH NEXT и оператором IF NOT EXISTS (в основном он будет вставлять первую запись, однако после этого курсор не будет перемещаться на следующую запись поэтому IF NOT EXISTS постоянно ложно). Это мой первый раз, используя курсор, поэтому надеялся, что кто-то сможет объяснить, что происходит/как заставить эту вещь работать!

DECLARE prod_cursor CURSOR FOR SELECT ProductCode FROM CourseToProduct WHERE CourseCode = @courseCode and (TerminationDate >= @expDate OR TerminationDate IS NULL) OPEN prod_cursor FETCH NEXT FROM prod_cursor INTO @productCode WHILE @@FETCH_STATUS = 0 BEGIN IF NOT EXISTS ( SELECT sNumber FROM AgentProductTraining WHERE @sNumber = sNumber and @courseCode = CourseCode and @productCode = ProductCode and @dateTaken = DateTaken ) BEGIN IF @sNumber IS NOT NULL BEGIN INSERT INTO AgentProductTraining ( sNumber, CourseCode, ProductCode, DateTaken, DateExpired, LastChangeOperator, LastChangeDate ) VALUES ( @sNumber, @courseCode, @productCode, @dateTaken, COALESCE(@expDate, 'NULL'), @lastChangeOperator, @lastChangeDate ) END END END CLOSE prod_cursor; DEALLOCATE prod_cursor; задан NealR 31 окт. '12 в 0:59 источник поделиться

qaru.site

Как оптимизировать этот код сценария t-sql, избегая цикла? MS SQL Server

Одна из ваших проблем заключается в том, что ваш оператор select в цикле извлекает все записи для LitraID = 8175, устанавливает номера строк, а затем фильтрует в заявлении об обновлении. Это происходит на каждой итерации.

Одним из способов этого было бы получить все идентификаторы для обновления, прежде чем вводить цикл и хранить их во временной таблице. Затем вы можете написать аналогичный запрос с тем, который у вас есть, но присоединяетесь к этой таблице идентификаторов.

Однако есть еще более простой способ, если вы знаете примерно, сколько записей имеет LitraID = 8175, и если они распределены по всей таблице, а не сгруппированы вместе с аналогичными идентификаторами.

DECLARE @batchSize INT DECLARE @minId INT DECLARE @maxId INT SET @batchSize = 10000 --adjust according to how frequently LitraID = 8175, larger numbers if infrequent SET @minId = 100000000 WHILE @minId <= 300000000 BEGIN SET @maxId = @minId + @batchSize - 1 IF @maxId > 300000000 BEGIN SET @maxId = 300000000 END BEGIN TRANSACTION T UPDATE MyTable SET DoorsReleased = ~DoorsReleased WHERE id BETWEEN @minId AND @maxId COMMIT TRANSACTION T SET @minId = @maxId + 1 END

Это будет использовать значение id для управления циклом, то есть вам не нужен дополнительный шаг для вычисления @iterationCount. Он использует небольшие партии, чтобы таблица не была заблокирована в течение длительного времени. В нем нет лишних операторов SELECT, и предложение WHERE в обновлении является эффективным, если id имеет индекс.

В каждой транзакции не будет точно такого же количества записей, но нет причин, по которым это необходимо.

Это устранит цикл

UPDATE MyTable set DoorsReleased = ~DoorsReleased WHERE LitraID = 8175 AND id BETWEEN 100000000 AND 300000000 AND DoorsReleased is not null -- if DoorsReleased is nullable -- AND DoorsReleased <> ~DoorsReleased</strike>

если вы настроены на цикл ниже НЕ будет работать Я думал, что ~ является частью имени столбца, но это не оператор

select 1; WHILE (@@ROWCOUNT > 0) BEGIN UPDATE top (100000) MyTable set DoorsReleased = ~DoorsReleased WHERE LitraID = 8175 AND id BETWEEN 100000000 AND 300000000 AND ( DoorsReleased <> ~DoorsReleased or ( DoorsReleased is null and ~DoorsReleased is not null ) ) END

Внутри транзакции я не думаю, что цикл будет иметь значение, поскольку журнал транзакций не может быть очищен. И размер партии 10 000 невелик. \

как указано в комментарии, если вы хотите использовать цикл, тогда попробуйте использовать id как row_number (), все эти петли дороги

вы можете использовать OFFSET

sqlserver.bilee.com