Лого на 91. НЕГ „Проф. Константин Гълъбов“

Модул 4 · Урок 8

Още за съхранените процедури

T-SQL като език за програмиране: локални променливи, IF/ELSE, WHILE, курсори за ред-по-ред достъп и транзакциите с COMMIT/ROLLBACK.

Локални променливи

В процедурите можем да пазим междинни резултати в локални променливи — както във функциите на C#. Декларираме ги с DECLARE @име тип (в един DECLARE — няколко променливи, дори от различни типове). Присвояваме със SET @име = израз или направо в заявка: SELECT @var = …. Извеждаме с PRINT.

CREATE PROCEDURE spStudNames
  @StudId int = 1
AS
BEGIN
  DECLARE @var varchar(50) = 'Няма такъв ученик';
  SELECT @var = CONCAT_WS(' ', name, surname, family) FROM Student
  WHERE idStudent = @StudId;
  PRINT @var;
END

Бележка

Стойността по премълчаване на @var („Няма такъв ученик“) остава, ако фактическият параметър не съществува в таблицата — иначе процедурата би извела Null.

Условни оператори и цикли

T-SQL предлага класическите конструкции — синтаксисът не се различава съществено от езиците за програмиране, а влагането е допустимо:

IF <условие> BEGIN <оператори> END
ELSE BEGIN <оператори> END

WHILE <условие> BEGIN <оператори> END

Пример: spNumPerYear сравнява броя на родените до края на 2002 г. и след него — две променливи, две SELECT COUNT заявки и вложен IF, който извежда „Родените през 2002 са повече.“, „…2003 са повече.“ или „…равен брой.“.

Курсори — ред по ред през таблицата

SQL е декларативен, но с курсор получаваме последователен достъп до редовете на таблица — почти като масив от обекти в C# (там достъпът е пряк, по индекс). Курсорът е указател към ред и работи със стойностите в реда, който сочи.

DECLARE @име CURSOR FOR <заявка SELECT>;
OPEN @име;                -- позиция ПРЕДИ първия ред
FETCH NEXT FROM @име INTO <локални променливи>;
WHILE @@FETCH_STATUS = 0
BEGIN
  ... FETCH NEXT ...
END
CLOSE @име; DEALLOCATE @име;
Модификатор на FETCHМести курсора върху…
NEXTследващия ред (най-често използваният)
PRIORпредишния ред
FIRST / LASTпървия / последния ред, откъдето и да сме
ABSOLUTE nn-тия ред от началото (при n<0 — от края)
RELATIVE nn реда напред (или назад при n<0) от позицията

Пример — spGirlList

Извежда момичетата от Student: няма атрибут за пол, но предпоследната цифра на ЕГН при жените е нечетна. Курсорът минава през всички редове, а IF SUBSTRING(@egn,9,1) % 2 <> 0 отпечатва само подходящите.

Транзакции

Ако процедура с няколко оператора се провали по средата, сървърът продължава със следващите — и базата може да остане в противоречиво състояние (изтрили сме стария ред, а нов не е записан). Транзакцията обединява операторите в едно цяло: или всички успяват, или базата остава непроменена.

BEGIN TRANSACTION;
  BEGIN TRY
    <операторите>
    SET @Result = 1;
  END TRY
  BEGIN CATCH
    SET @Result = 0;
  END CATCH
IF @Result = 1 COMMIT; ELSE ROLLBACK;

ACID и видовете сривове

  • ACID (Atomicity, Consistency, Isolation, Durability) — стандартният набор от свойства за надеждна обработка на транзакции: базата е последователна тогава и само тогава, когато съдържа резултатите от успешни транзакции.
  • Отказ на транзакция — лош вход, нарушение на последователността, прекъсване на СУБД.
  • Отказ на системата — грешка в кода на СУБД, операционната система или хардуерна повреда.
  • Срив на носителя — устройството за съхранение не може да се чете/записва; най-рядък, но най-тежък.

Практикум

1) Съхранете процедурите от урока и ги изпълнете с различни параметри. 2) Оформете свои стари заявки като процедури. 3) С курсор изведете списък с име, съкратено презиме (1 или 2 букви + точка според гласна/съгласна) и фамилия.

Какво трябва да запомниш

  • DECLARE @var тип; SET/SELECT за присвояване; PRINT за извеждане.
  • IF/ELSE и WHILE — с блокове BEGIN … END, влагането е допустимо.
  • Курсор: DECLARE…CURSOR FOR → OPEN → FETCH NEXT…INTO → @@FETCH_STATUS → CLOSE + DEALLOCATE.
  • Транзакция: BEGIN TRANSACTION → TRY/CATCH → COMMIT или ROLLBACK.
  • ACID гарантира: базата съдържа само резултати от успешни транзакции.