BD10 ProgrammingSQL
BD10 ProgrammingSQL
Índice
• Script e Batch
• Cursor
• Stored Procedure
• User Defined Function
• Trigger
1
5/30/21
Batch
2
5/30/21
Batch - Utilização
Script
3
5/30/21
Variáveis
• Declaração:
§ DECLARE @x varchar(10) = ‘Ola’
§ DECLARE @min_range int, @max_range int
• Atribuição de um valor:
§ SET @x = ’Kabung’
§ SET @min_range = 0, @max_range = 100
Resultado
4
5/30/21
Resultado
Select to Variable
10
último tuplo
10
10
5
5/30/21
-- Exemplos
PRINT ‘ola’;
11
11
• BEGIN … END
• IF … ELSE
• CASE … WHEN
• WHILE
12
12
6
5/30/21
BEGIN … END
13
13
IF … ELSE
IF Boolean_expression
statement | block_of_statements
[ELSE
statement | block_of_statements ]
-- Exemplos
IF (SELECT ytd_sales FROM titles WHERE title_id='PC1035') > 5000
PRINT 'Year-to-date sales are greater than $5,000 for PC1035.‘
14
7
5/30/21
WHILE
WHILE Boolean_expression
SQL_statement | block_of_statements |
[BREAK] | [CONTINUE]
-- Exemplos
WHILE (SELECT AVG(royalty) FROM roysched) < 25
BEGIN
UPDATE roysched SET royalty = royalty * 1.05;
IF (SELECT MAX(royalty) FROM roysched) > 27
BREAK;
ELSE
CONTINUE;
END;
DECLARE @i as int = 1;
WHILE @i < 100
BEGIN
IF (@i % 2) = 0
print str(@i) + ' - Par';
ELSE
print str(@i) + ' - Impar’;
SET @i += 1; 15
END;
15
CASE … WHEN
CASE input_expression
WHEN when_expression THEN result_expression
[WHEN when_expression THEN result_expression…n]
[ELSE else_result_expression ]
END
-- Exemplo
SELECT OrderID, CustomerID ,
EmployeeName =
CASE EmployeeID
WHEN 1 THEN 'Mario'
WHEN 2 THEN 'Julio'
WHEN 3 THEN 'Vasco'
WHEN 4 THEN 'Sousa'
WHEN 5 THEN 'Rui'
ELSE 'desconhecido'
END
FROM [Orders] 16
16
8
5/30/21
Tabelas Temporárias
17
18
9
5/30/21
19
20
10
5/30/21
21
22
22
11
5/30/21
Cursor
23
23
Cursor
12
5/30/21
Cursor – 5 steps
1. Declaração
-- SQL-92
DECLARE CursorName [CursorOptions] CURSOR
FOR Select Statement;
-- T-SQL
DECLARE CursorName CURSOR [CursorOptions]
FOR Select Statement;
2. Open
-- Open to retrieve data
OPEN CursorName;
3. Fetch
/* Moves to the next row and assigns the values from each column returned by
the cursor into a local variable */
FETCH [Direction] CursorName [INTO @Variable1, @Variable2, ...];
-- T-SQL offers @@fetch_status function to report the state of the cursor after
the last FETCH command (0: OK; -1: Fail, end off record set; -2: Fail, tuple not available)
4. Close
-- Close cursor. Can be opened again (2.Open)
CLOSE CursorName;
5. DEALLOCATE
-- Release cursor. 25
DEALLOCATE CursorName;
25
Cursor - Exemplo
Objectivo: Número de produtos distintos e total absoluto encomendados por cada cliente
DECLARE @custID as nchar(5), @prevCustID as nchar(5), @prodID as int,
@qty as int, @totalQty as int, @cnt as smallint;
OPEN c;
CustOrdersProducts
FETCH C INTO @custID, @prodID, @qty;
WHILE @@FETCH_STATUS = 0
BEGIN
if @prevCustID <> @custID
BEGIN
PRINT @prevCustID + ' - ' + CAST(@cnt as varchar) + ' - ' + CAST(@totalQty as
varchar);
SELECT @prevCustID = @custID, @totalQty = 0, @cnt = 0;
END;
CLOSE C;
DEALLOCATE C; 26
26
13
5/30/21
Objectivo:
Implementação Alternativa com Consulta baseada em Álgebra Relacional
SELECT CustomerID, count(ProductID) as nprod, sum(Quantity) as totalQty
FROM CustOrderProducts
GROUP BY CustomerID
ORDER BY CustomerID;
Resultados
236 ms 7 ms
pesca à linha pesca com rede
27
27
• Iterating over DDL code: When DDL code must be dynamically executed multiple times,
using a cursor is the appropriate solution.
§ Sometimes it’s necessary to iterate over multiple rows or columns, generating a dynamic SQL statement for each
row or column.
• Cumulative Totals/Running Sums: While there are set-based solutions, a cursor is the
best-performing solution in these cases because it only has to add the next row’s value to
the cumulative value.
28
Source: Microsoft SQL Server 2008 Bible
28
14
5/30/21
Cursor - [CursorOptions]
29
Lista não exaustiva
29
Stored Procedures
Procedimentos
30
30
15
5/30/21
• O procedimento pode:
§ Ter parâmetros de entrada
§ Ter valor de retorno (parâmetros de saída, return success ou failure
status messages) 31
§ Devolver um conjunto de registos (tuplos)
31
• Security: Locking down the tables and providing access only through
stored procedures is a standard best practice for database 32
development. Source: Microsoft SQL Server 2008 Bible
32
16
5/30/21
33
Sintaxe:
CREATE PROC[EDURE] procedure_name
[ @parameter_name data_type] [= default] OUTPUT][,...,n]
AS
T-SQL_statement(s)
34
17
5/30/21
35
Sintaxe:
ALTER PROC[EDURE] procedure_name
[ @parameter_name data_type] [= default] [OUTPUT] [,...,n]
AS
T-SQL_statement(s)
Sintaxe:
DROP PROC[EDURE] procedure_name
• Elimina um procedimento
-- if exists, delete the procedure
IF Object_Id('Production.ProductList', 'P') IS NOT NULL 36
DROP PROCEDURE Production.ProductList;
36
18
5/30/21
37
Sintaxe:
EXEC[CUTE] procedure_name [@parameter_name data_type]
38
38
19
5/30/21
-- Utilização
DECLARE @ProdName VARCHAR(25);
EXEC dbo.GetProductName ‘1001’, @ProdName OUTPUT;
PRINT @ProdName; 39
39
40
20
5/30/21
41
T-SQL RAISERROR
-- Exemplo: RAISERROR
RAISERROR (’Nao foi possivel actualizar registo em %s.’, 14, 1, ‘Customer’);
42
42
21
5/30/21
<SQL code>;
CREATE PROCEDURE uspTryCatchTest
AS
BEGIN TRY
SELECT 1/0
END TRY END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber
END CATCH;
GO
EXEC uspTryCatchTest;
43
43
44
22
5/30/21
45
45
UDF - Vantagens
46
46
23
5/30/21
UDF - Tipos
47
47
UDF Escalar
Sintaxe:
CREATE FUNCTION function_name
[ @param_name data_type] [= default] [ READONLY ][,...,n]
RETURNS return_data_type
AS
T-SQL_statement(s)
48
24
5/30/21
GO
SELECT dbo.Revenue_Day(GETDATE())
GO
SELECT dbo.fsMultiply (3,4), dbo.fsMultiply (7, DEFAULT);
49
• Determinísticas
§ Os mesmos parâmetros de entrada produzem o mesmo valor de
retorno.
§ Não são permitidas funções não-determinísticas dentro das UDF.
• newid(), rand(), etc
• Não são permitidos updates à base de dados ou invocação
do comando DBCC.
• Em termos de valor de retorno não permite:
§ BLOB (binary large object) - text, ntext, timestamp, image data-
type, etc.
§ Table variables
§ Cursores
• Não permite TRY...CATCH ou RAISERROR.
• Recursividade limitada a 32 níveis. 50
50
25
5/30/21
Sintaxe:
CREATE FUNCTION function_name
[ @param_name data_type] [= default] [ READONLY ][,...,n]
RETURNS TABLE
AS
T-SQL_statement {RETURN SELECT statement}
• Similares a vistas
§ Ambas são wrapers para construções SELECT
§ Tem as mais valias das vistas acrescido do facto de
suportar parâmetros de entrada.
51
51
GO
SELECT * FROM dbo.AveragePricebyItems (15.00)
GO
SELECT * FROM dbo.ftPriceList(DEFAULT, ‘20020220’); 52
52
26
5/30/21
Sintaxe:
CREATE FUNCTION function_name
[ @param_name data_type] [= default] [ READONLY ][,...,n]
RETURNS @return_variable TABLE <table_type_definition>
AS
T-SQL_statement
53
53
GO
SELECT * FROM dbo.AveragePricebyItems2 (15.00);
CREATE FUNCTION dbo.ftPriceAvg() RETURNS @Price TABLE (Code char(10), EffectiveDate datetime,
Price money)
AS
BEGIN
INSERT @Price (Code, EffectiveDate, Price)
SELECT Code, EffectiveDate, Price
FROM Product JOIN Price ON Price.ProductID = Product.ProductID;
GO 54
SELECT * FROM dbo.ftPriceAvg();
54
27
5/30/21
SP versus UDF
56
• transactions – OK • transaction - NOK
56
Trigger
57
57
28
5/30/21
Trigger - Definição
58
29
5/30/21
60
61
30
5/30/21
Sintaxe:
-- Criação
CREATE TRIGGER trigger_name ON <tablename>
AFTER | INSTEAD OF { [INSERT] [,] [UPDATE] [,] [DELETE]}
AS
SQL_Statement
-- Activar | Desactivar
ALTER TABLE <tablename> ENABLE | DISABLE TRIGGER trigger_name
ou
ENABLE | DISABLE TRIGGER trigger_name ON <tablename>
-- Eliminar
DROP TRIGGER trigger_name ON <tablename>
62
62
Trigger - After
63
63
31
5/30/21
?
SET NOCOUNT ON;
INSERT INTO dbo.[Order Details] values (10248, 14, 18.6, 20, 0.15);
INSERT INTO dbo.[Order Details] values (10248, 14, 18.6, 200, 0.15);
64
64
Trigger – Instead of
65
32
5/30/21
66
66
IF (@iplocation) is null
RAISERROR('Project Inexistent.', 16, 1);
ELSE
BEGIN -- You can have different Pno with same Plocation
IF (SELECT count(distinct Plocation) FROM Project join Works_on on Pno=Pnumber
WHERE essn=@issn AND plocation<>@iplocation) >= 1
RAISERROR('Not allowed to have employee working in Projects with different Plocations.', 16, 1);
ELSE
INSERT INTO works_on SELECT * FROM inserted; -- chamada recursiva
END
END
END
GO
67
33
5/30/21
69
§ columns_updated()
• Retorna um bitmapped varbinary representando as colunas
alteradas. O seu tamanho depende do número de colunas da tabela.
Se uma coluna foi alterada então o seu bit está a true. Temos de
utilizar bitwise operators para determinar quais as colunas
alteradas. 70
70
34
5/30/21
Triggers - Limitações
71
71
72
72
35
5/30/21
Resumo
• Script e Batch
• Cursor
• Stored Procedure
73
73
36