2014-02-12 3 views
1

Я прочитал ответ, в котором говорилось, что вы не хотите использовать петли WHILE на SQL Server. Я не понимаю этого обобщения. Я довольно новичок в SQL, поэтому пока не могу понять объяснение. Я также читал, что вы действительно не хотите использовать курсоры, если не хотите. Результаты поиска, которые я нашел, слишком специфичны для представленной проблемы, и я не мог извлечь из них полезную технику, поэтому я представляю это вам.Sql Server 2008 r2 Использование цикла WHILE внутри функции

Что я пытаюсь сделать, это взять значения в файле клиента и сократить их там, где это необходимо. Здесь нужно сделать пару вещей. Я не могу просто взломать значения полей. У моей компании есть стандартные сокращения, которые будут использоваться. Я поставил их в таблице, Сокращения. таблица имеет LongName и ShortName. Я не хочу просто сокращать каждые LongName в строке. Я хочу применить обновление только до тех пор, пока длина поля слишком длинная. Вот почему мне нужен цикл WHILE.

Мой мыслительный процесс был таким образом:

CREATE FUNCTION [dbo].[ScrubAbbrev] 
(@Field nvarchar(25),@Abbrev nvarchar(255)) 
RETURNS varchar(255) 
AS 
BEGIN 
    DECLARE @max int = (select MAX(stepid) from Abbreviations) 
    DECLARE @StepID int = (select min(stepid) from Abbreviations) 
    DECLARE @find varchar(150)=(select Longname from Abbreviations where [email protected]) 
    DECLARE @replace varchar(150)=(select ShortName from Abbreviations where [email protected]) 
    DECLARE @size int = (select max_input_length from FieldDefinitions where FieldName = 'title') 
    DECLARE @isDone int = (select COUNT(*) from SizeTest where LEN(Title)>(@size)) 

    WHILE @StepID<[email protected] or @isDone = 0 and LEN(@Abbrev)>(@size) and @Abbrev is not null 
    BEGIN 
     RETURN 
     REPLACE(@Abbrev,@find,@replace) 
     SET @[email protected]+1 
     SET @find =(select Longname from Abbreviations where [email protected]) 
     SET @replace =(select ShortName from Abbreviations where [email protected]) 
     SET @isDone = (select COUNT(*) from SizeTest where LEN(Title)>(@size)) 
    END 
END 

Очевидно, что RETURN должен идти в конце, но мне нужно сбросить мои переменные к следующему @stepID, @find и @replace.

Является ли это одним из тех случаев, когда мне придется использовать курсор (который я еще не написал)?

ответ

1

Как правило, вы не хотите использовать курсоры или циклы в SQL, потому что они обрабатывают только одну строку за раз и, следовательно, работают очень плохо. SQL разработан и оптимизирован для обработки (потенциально очень большой) наборов данных, а не отдельных значений.

Вы можете вынесем в то время цикла, делая что-то вроде этого:

UPDATE t 
SET t.targetColumn = a.ShortName 
FROM targetTable t 
INNER JOIN Abbreviations a 
ON t.targetColumn = a.LongName 
WHERE LEN(t.targetColumn) > @maxLength 

Это обобщается и вам нужно будет настроить его в соответствии с вашей конкретной модели данных, но вот что происходит:

Для каждой строки в «targetTable» установите значение «targetColumn» (то, что вы хотите сократить) до соответствующей аббревиатуры (найдено в Abbreviations.ShortName) iff: текущее значение имеет стандартизованную аббревиатуру (внутреннее соединение) и текущее значение больше желаемого (условие where).

Вам нужно будет добавить целочисленный параметр или локальную переменную @maxLength, чтобы указать, что составляет «слишком длинный». Этот запрос обрабатывает целевую таблицу сразу, обновляя значение в целевом столбце для каждой подходящей строки, в то время как функция будет находить только аббревиатуру для одного элемента (пересечение одной строки и одной колонки) за раз.

Обратите внимание, что это не будет делать ничего, если значение слишком длинное, но не имеет стандартной аббревиатуры. Ваш существующий код имеет такое же ограничение, поэтому я предполагаю, что это желаемое поведение.

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

+0

Я вижу, что вы говорите, поскольку все, что должно оценивать каждую линию, было бы весомым процессом. Это контактная информация, поэтому я должен будет применить ее к каждому полю на основе имеющейся длины. Кроме того, я не могу заменить все поле. То, что я смотрю на достижение, превращает «научный сотрудник биотехнологии» в «Профессор, кафедра патологии и лабораторной медицины, UBC». Именно поэтому я использую функцию «REPLACE», а не 'SET'. –

+0

Несомненно, имеет смысл. Похоже, у вас может быть более одного аббревиатуры на запись. В этом случае вы хотите присоединиться к targetColumn, например, «%» + LongName + «%» и использовать замену в инструкции обновления. Могут потребоваться некоторые настройки, чтобы избежать ложных срабатываний (например, частичное совпадение слов), но общий метод одинаков: используйте подход на основе набора, чтобы избежать проблем с производительностью циклов. –

+0

Спасибо за помощь. Я передумаю этот проект на следующей неделе. По-видимому, я пока не могу продвинуться. : -/ –

Смежные вопросы