Локални променливи
В процедурите можем да пазим междинни резултати в локални променливи — както във функциите на 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 n | n-тия ред от началото (при n<0 — от края) |
RELATIVE n | n реда напред (или назад при 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 гарантира: базата съдържа само резултати от успешни транзакции.