שפת Transact-SQL היא שפה פרוצדורלית שמרחיבה את שפת SQL ומאפשרת שימוש במשתנים, פונקציות, תנאים, לולאות וכו'
מושגי יסוד
- Batch – אוסף פקודות שנשלחות לשרת יחד.
- GO – מפריד בין Batch ל-Batch.
- [] – לשימוש עם מילים שמורות או שמות עם רווחים.
- @ – סימון למשתנה.
- #- סימון למשתנה זמני, מקומי.
- ##- סימון למשתנה זמני, גלובלי.
הגדרת משתנים מקומיים – Local Variables
משתנים מקומיים מוגדרים בתוך משפט SQL או פרוצדורה עם מילת המפתח DECLARE. משתנה מקומי מחזק ערך אחד בךבד.
DECLARE @local_variable data_type [,@local_variable data_type,…]
דוגמא:
DECLARE @CustomerID CHAR(5)
DECLARE @CustomerID CHAR(5), @CustomerName VARCHAR(30)
השמת ערך למשתנה מקומי
אתחול משתנים מתבצע על ידי פקודת SET. כל משתנה מאותחל על ידי SET נפרד.
SET @local_variable = value
דוגמא.
-- הצהרה של משתנה והשמת ערך
DECLARE @CustomerID CHAR(5)
SET @CustomerID = 'AROUT'
-- שימוש בערך של המשתנה
SELECT CompanyName, ContactName, Phone
FROM Customers
WHERE CustomerID = @CustomerID
השמה מתוך פעולת Select.
-- מבנה
DECLARE @Local_Variable_1 <Data_Type>, @Local_Variable_2 <Data_Type>,
SET @Local_Variable_1 = (SELECT <Column_1> from <Table_Name> where <Condition_1>)
-- דוגמא
DECLARE @COURSE_NAME VARCHAR (10)
SET @COURSE_NAME = (select Tutorial_name from Guru99 where Tutorial_ID = 3)
PRINT @COURSE_NAME
אפשר לקבל ערך מתוך בסיס הנתונים על ידי SELECT. השאילתא חייבת להחזיר שורה אחת בלבד.
-- מבנה
DECLARE @LOCAL_VARIABLE <Data_Type>
SELECT @LOCAL_VARIABLE = <Value>
--דוגמא
DECLARE @COURSE_ID INT
SELECT @COURSE_ID = 5
-- מבנה לכמה ערכים
DECLARE @Local_Variable _1 <Data_Type>, @Local_Variable _2 <Data_Type>,
SELECT @Local_Variable _1 = <Value_1>, @Local_Variable _2 = <Value_2>
-- דוגמא. יכול לעשות השמה לכמה ערכים במקביל
DECLARE @COURSE_ID as INT, @COURSE_NAME AS VARCHAR(5)
SELECT @COURSE_ID = 5, @COURSE_NAME = 'UNIX'
-- מבנה השמה מתוך שאילתא. השאילתא חייבת להחזיר שורה אחת ועמודה אחת, כלומר ערך ספציפי.
DECLARE @Local_Variable_1 <Data_Type>, @Local_Variable _2 <Data_Type>,
SELECT @Local_Variable _1 = (SELECT <Column_1> from <Table_name> where <Condition_1>)
-- דוגמא
DECLARE @COURSE_NAME VARCHAR (10)
SELECT @COURSE_NAME = (select Tutorial_name from Guru99 where Tutorial_ID = 1)
הדפסת משתנים
בחוצץ MESSAGE. מקבל רק מחרוזות.
PRINT @local_variable
בחוצץ RESULT.
SELECT @local_variable
תנאים Conditions
פקודת IF.
IF Boolean_expression
{sql_statement | statement_block}
[ELSE
{sql_statement | statement_block}]
-- בלוק ליותר מפקודה אחת
BEGIN
{sql_statement, statement_block}
END
דוגמא
DECLARE @x INT
SET @x = 1
IF (1 = @x)
BEGIN
PRINT 'You are number one! '
END
ELSE
BEGIN
PRINT 'Loser ;-( '
END
שימוש ב – Exists בתנאי
EXISTS מאפשר לבחון אם תת השאילתה החזירה שורות כלשהן ומחזירה ערך TRUE או FALSE.
דוגמא:
IF EXISTS (SELECT *
FROM Orders
WHERE CustomerID = 'VINET')
BEGIN
PRINT 'The Customer has Order'
END
ELSE
BEGIN
DELETE Customers
WHERE CustomerID = 'VINET'
PRINT 'Customer deleted'
END
שימוש בביטויי Case
CASE הוא ביטוי המספק אמצעי להחזרת נתונים שונים המבוסס על בדיקת הערך המוחזר.
דוגמא.
DECLARE
@x INT,
@Case_result VARCHAR(20)
SET @x =1
SET @Case_Result = CASE @x
WHEN 1 THEN 'You are number one!'
WHEN 2 THEN 'Almost …'
ELSE 'Loser :-('
END
PRINT @Case_Result
@@ROWCOUNT
משתנה גלובלי אשר מחזיר את מספר הרשומות שהושפעו מפקודה מסויימת.
לולאות – While
לולאת While מאפשרת ביצוע מחזורי.
break – הפסקת הביצוע של הלולאה.
continue – הפסקה של האיטרציה הנוכחית של הלולאה.
-- מבנה
WHILE Boolean_expression
{sql_statement | statement_block}
דוגמא
-- מבנה
DECLARE @n INT
SET @n = 1
WHILE (SELECT COUNT(*) FROM Employees) >= @n
BEGIN
IF (SELECT LastName FROM Employees
WHERE EmployeeID = @n) = 'King'
BEGIN
PRINT 'King EmployeeID =' + CAST(@n AS VARCHAR(2))
BREAK
END
ELSE
SET @n = @n + 1
END
לולאות GOTO
לולאת GOTO מאפשרת הרצה מחזורית של משפטי ה-SQL כל עוד תנאי שהוגדר מתקיים.
הלולאה תתבצע לפחות פעם אחת והתנאי יבדק לאחר הביצוע הראשון.
LABEL היא לא מילה שמורה, אפשר להשתמש בכל מחרוזת.
-- מבנה
Label:
Sql_statments | statement block
IF condition GOTO Label
דוגמא:
DECLARE @emp_id NUMERIC(4),
@name VARCHAR(30),
@b_date DATETIME
SET @emp_id = 4
LABEL:
SELECT @name =lastname, @b_date = birthdate
FROM employees
WHERE employeeid = @emp_id
PRINT @name + CAST(@b_date AS VARCHAR)
SET @emp_id = @emp_id +1
IF @name LIKE '%a%' GOTO LABEL
PRINT CHAR(10)+'That''s how GOTO LOOP works...'
טיפול בשגיאות
Try… Catch
יש לבצע שימוש בטרנזקציות – במידה ופקודה אחת נכשלת, כל קודמותיה ייכשלו. אחרת, חלק מהפעולות מתבצעות ורק הפעולה עם השגיאה תטופל בהתאם ותכשל.
-- מבנה
BEGIN TRY
Sql statements
END TRY
BEGIN CATCH
Sql statements
END CATCH
ניתן לתפוס שגיאות שהתקבלו על ידי שימוש ב:
ERROR_MESSAGE() – ההודעה שהתקבלה
ERROR_NUMBER() – מספר השגיאה
ERROR_LINE() – אינדיקציה למספר השורה בה התקבלה השגיאה
ERROR_PROCEDURE() – הפרוצדורה בה קרתה השגיאה
ERROR_SEVERITY() – חומרת השגיאה
ERROR_STATE() – במידה ויש DISTREBUTED DATE BASES
RAISERROR
דרך נוספת לטיפול בשגיאות, השגיאה עולה בצורה יזומה.
RAISERROR יוצא מהבלוק, שאר הפעולות בבלוק לא יבוצעו ותוצג הודעת שגיאה.
RAISERROR לא סוגר טרנזקציה ולא מבצע ROLLBACK.
-- מבנה
RAISERROR (message_string | message_id | variable ,severity, state [,])
ניתן להוסיף שגיאה ידנית בשימוש ב-system procedure אשר נקראת addmessage.
EXEC sp_addmessage
@msgnum = value over 50000,
@severity = value between 1 and 25,
@msgtext = ‘The message’
@@ERROR – משתנה גלובלי אשר מחזיר את מספר השגיאה האחרונה שהתרחשה. 0 מסמן הצלחה, כל מספר אחר שגיאה.
תרגול T-SQL BASIC
-- ex1
DECLARE @FirstVar CHAR(30), @SecondVar VARCHAR(30)
SET @FirstVar = 'MY FIRST'
SET @SecondVar = 'VARIABLE'
PRINT @FirstVar+' '+@SecondVar
-- ex2
DECLARE @StrPrompt CHAR(30), @TodayDate Date
SET @StrPrompt = 'THE DATE TODAY IS: '
SET @TodayDate = getdate()
PRINT @StrPrompt+cast(@TodayDate as char)
-- ex3
DECLARE @Emp4Name CHAR(30)
SELECT @Emp4Name = (select lastName from Employees where EmployeeID = 4)
PRINT @Emp4Name
-- ex4
DECLARE @Prod5Name CHAR(30), @Prod5Cat CHAR(30)
SELECT @Prod5Name = (select ProductName from Products where ProductID = 5)
SELECT @Prod5Cat = (select c.CategoryName from Products p
inner join Categories c on p.CategoryID = c.CategoryID where p.ProductID = 5)
PRINT @Prod5Name+@Prod5Cat
-- ex5
DECLARE @Prod9Price INT
SELECT @Prod9Price = (select unitprice from Products where ProductID = 17)
IF (@Prod9Price > 50)
BEGIN
PRINT 'I LIKE THIS PRODUCT '
END
ELSE
BEGIN
PRINT 'I DO NOT LIKE THIS PRODUCT '
END
select * from Products
-- ex6
DECLARE @ProdName CHAR(50), @ProdPrice INT
SELECT @ProdName = 'Tarte au sucre'
SELECT @ProdPrice = (select unitprice from Products where ProductName = @ProdName)
IF (@ProdPrice < 20)
BEGIN
set @ProdPrice = @ProdPrice * 1.1
PRINT 'New 10% price '+cast(@ProdPrice as char)
END
else IF (@ProdPrice >= 20 and @ProdPrice < 40)
BEGIN
set @ProdPrice = @ProdPrice * 1.2
PRINT 'New 20% price '+cast(@ProdPrice as char)
END
ELSE
BEGIN
set @ProdPrice = @ProdPrice * 1.5
PRINT 'New 50% price '+cast(@ProdPrice as char)
END
-- ex7
DECLARE @n INT, @EmpLastName CHAR(20)
SET @n = 1
WHILE (SELECT COUNT(*) FROM Employees) >= @n
BEGIN
select @EmpLastName = (SELECT LastName FROM Employees WHERE EmployeeID = @n)
IF @EmpLastName like '%e%'
BEGIN
PRINT cast(@n as char)+' - Letter e in last name = ' + @EmpLastName
SET @n = @n + 1
END
ELSE
SET @n = @n + 1
END
-- ex8
DECLARE @cat_name VARCHAR(30),
@cat_num INT
SET @cat_num = 4
LABEL:
SELECT *
FROM categories
WHERE Categoryid = @cat_num
SELECT @cat_name = categoryname
FROM categories
WHERE categoryid = @cat_num
SET @cat_num = @cat_num + 1
IF @cat_name LIKE '%a%'
GOTO LABEL
ELSE
SELECT 'NO MORE CATEGORIES WITH THE LETTER A!'
-- מעבר בלולאה על כל הרשומות שיש לי בטבלה
-- פעולה יקרה, אם אין צורך לא משתמשים בה
DECLARE
@product_name VARCHAR(250),
@list_price DECIMAL;
DECLARE cursor_product CURSOR
FOR SELECT
product_name,
list_price
FROM
production.products; --50
OPEN cursor_product;
FETCH NEXT FROM cursor_product INTO
@product_name,
@list_price;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @product_name + CAST(@list_price AS varchar);
FETCH NEXT FROM cursor_product INTO
@product_name,
@list_price;
END;
CLOSE cursor_product;
DEALLOCATE cursor_product;