Procedury składowane, funkcje i wyzwalacze Struktura bazy danych Tabela Oddziały ID Nazwa Adres 10 POZNAN Kwiatowa 3 20 WARSZAWA al. Jerozolimskie 22 30 KRAKOW Planty 14 40 WROCLAW Nad Odra 16 50 GDANSK Portowa 30 Tabela Stanowiska Stanowisko Placa_min Placa_max BRYGADZISTA 2510,00 3750,00 DYREKTOR 8100,00 9200,00 KIEROWNIK 3800,00 5500,00 MONTER 1300,00 2500,00 PRAKTYKANT 1150,00 1250,00 SEKRETARKA 1270,00 2050,00 Tabela Pracownicy (=Zatrudnieni ID Nazwisko Stanowisko Szef Zatrudniony Placa_pod Placa_dod ID_Oddz 100 SUMINSKI DYREKTOR NULL 1968-01-01 8130,00 420,50 10 110 BARTCZAK KIEROWNIK 100 1973-05-01 4350,00 210,00 40 120 MALINOWSKI KIEROWNIK 100 1977-09-01 4070,00 NULL 30 130 BRZEZINSKI KIEROWNIK 100 1968-07-01 4960,00 NULL 20 140 ZABLOCKI BRYGADZISTA 130 1975-09-15 4830,00 105,00 20 150 LEWANDOWSKI BRYGADZISTA 130 1977-09-01 2645,50 NULL 20 160 KOPROWSKI BRYGADZISTA 130 1985-03-01 2590,00 NULL 20 170 JEZIERSKI MONTER 130 1992-10-01 1439,70 80,50 20 180 BOGULA SEKRETARKA 100 1985-02-20 1410,20 NULL 10 190 MALINIAK MONTER 140 1993-09-01 1371,00 NULL 20 200 URBANIAK PRAKTYKANT 140 1994-07-15 908,00 NULL 30 210 CELINSKI PRAKTYKANT 130 1993-10-15 950,00 170,60 30 220 KOWAL MONTER 110 1993-01-10 1480,00 NULL 20 230 HANTCZAK MONTER 120 1992-09-01 1480,00 90,00 30 IF OBJECT_ID('Nazwa-procedury','P' IS NOT NULL DROP PROCEDURE Nazwa-procedury CREATE PROCEDURE Nazwa-procedury ( @Parametr-1 typ-parametru [= wartość-domyślna] [OUTPUT] {@Parametr-2 typ-parametru [= wartość-domyślna] [OUTPUT] } {Komendy SQL} BAD210 Strona 1
IF OBJECT_ID('Nazwa-funkcji','FN' IS NOT NULL DROP FUNCTION Nazwa-funkcji CREATE FUNCTION Nazwa-funkcji ( @Parametr-1 typ-parametru [= wartość-domyślna] [OUTPUT] {@Parametr-2 typ-parametru [= wartość-domyślna] [OUTPUT] } RETURNS Typ-funkcji DECLARE @Wynik-funkcji Typ-funkcji {Komendy SQL ustalające wynik funkcji} RETURN(@Wynik-funkcji Zadania - Procedury Zad 1. Napisz procedurę PODWYZKA, która wszystkim pracownikom oddziału (parametr podniesie płacę podstawową o podany procent (parametr. Domyślnie podwyżka powinna wynosić 15%. IF OBJECT_ID('Podwyzka','P' IS NOT NULL DROP PROCEDURE Podwyzka CREATE PROCEDURE Podwyzka ( @Oddzial @Procent Skrypt testujący: TRAN -- Rozpoczęcie transakcji SELECT TOP 5 Placa_pod, * FROM Zatrudnieni EXEC Podwyzka 10, 50 SELECT TOP 5 Placa_pod, * FROM Zatrudnieni -- Wycofanie zmian 2. Dodaj do powyższej procedury obsługę błędu jeśli podano identyfikator nieistniejącego zespołu to procedura powinna zasygnalizować odpowiedni błąd. Wskazówka 1: Skorzystać z funkcji RAISERROR. Wskazówka 2: W skrypcie testującym skorzystać z bloków TRY i CATCH. RAISERROR (N'Błędny numer oddziału: %d ', -- Message text. 16, -- Severity, severity 11-19 will cause execution to jump to CATCH block 1, -- State @Oddzial -- Parameter Skrypt testujący: TRAN -- Rozpoczęcie transakcji SELECT TOP 5 Placa_pod, * FROM Zatrudnieni BAD210 Strona 2
TRY EXEC Podwyzka 97,50 SELECT TOP 5 Placa_pod, * FROM Zatrudnieni TRY CATCH SELECT ERROR_NUMBER( ErrorNumber,ERROR_MESSAGE( ErrorMessage; CATCH -- Wycofanie zmian 3. Napisz procedurę LICZBA_PRACOWNIKOW, która dla podanego kodu oddziału (parametr zwróci liczbę pracowników zatrudnionych w tym oddziale. Liczba pracowników powinna być zwrócona przez argument wyjściowy. Procedura powinna obsługiwać podanie nieprawidłowej nazwy oddziału. Skrypt testujący: DECLARE @Oddzial INT DECLARE @Ilosc INT SET @Oddzial=10 TRY EXEC Ilosc_pracownikow @Oddzial, @Ilosc OUTPUT PRINT 'Ilość pracowników w oddziale: ' + CT(@oddzial as VARCHAR(2 + ' wynosi: ' + CT(@Ilosc VARCHAR(10 TRY CATCH SELECT ERROR_NUMBER( ErrorNumber,ERROR_MESSAGE( ErrorMessage; CATCH 4. Napisz procedurę NOWY_PRACOWNIK, która będzie służyła do wstawiania nowych pracowników do tabeli Zatrudnieni. Parametrami procedury mają być nazwisko nowego pracownika, kod oddziału, nazwisko jego szefa i wartość płacy podstawowej. Domyślną datą zatrudnienia jest bieżąca data, domyślnym etatem MONTER. Procedura ma obsługiwać błędy podania istniejącego nazwiska, błędnego zespołu i błędnego nazwiska szefa. W tym celu uzupełnij poniższy wzór. IF OBJECT_ID('','' IS NOT NULL DROP PROCEDURE Nowy_pracownik CREATE PROCEDURE Nowy_pracownik ( @Nazwisko, @Oddzial, @NazwiskoSzefa, @Placa_pod, @Stanowisko = '', @Zatrudniony DATETIME = NULL BAD210 Strona 3
--1. Zadeklaruj nowe zmienne @Szef i @ID typu INT DECLARE DECLARE --2. Ustal ID szefa na podstawie nazwiska SET @Szef = (SELECT WHERE Nazwisko = --3. Ustal nowe ID pracownika. Nowe ID jest równe MAX istniejących ID + 10 SET @ID = ( ISNULL(MAX(ID,0+10 FROM --4. Jeśli data zatrudnienia nie została podana (jest NULL, pobierz datę dzisiejszą IF @Zatrudniony SET @Zatrudniony = -- 5. Jeśli Nazwisko już istnieje wywołaj bląd i zakończ procedurę IF EXISTS (SELECT ID FROM Zatrudnieni WHERE RAISERROR (N'Nazwisko %s ju istnieje', -- Message text. 16, -- Severity, severity 11-19 will cause execution to jump to CATCH block 1, -- State TO ProcEnd -- 6. Jeśli ID szefa nie jest prawidłowe wywołaj bląd i zakończ procedurę IF RAISERROR (N'B³êdne nazwisko szefa: %s', -- Message text. 16, -- Severity, severity 11-19 will cause execution to jump to CATCH block 1, -- State TO ProcEnd -- 7. Jeżeli kod oddziału nie jest prawidłowy wywołaj bląd i zakończ procedurę IF NOT EXISTS ( RAISERROR (N'Błędny numer oddziału: %d', -- Message text. 16, -- Severity, severity 11-19 will cause execution to jump to CATCH block 1, -- State TO ProcEnd --8. Wstaw nowe dane INSERT INTO Zatrudnieni (ID,Nazwisko,ID_Oddz,Stanowisko,Szef,Zatrudniony,Placa_pod VALUES ( ProcEnd: BAD210 Strona 4
-- Skryp testujący procedurę TRAN -- Rozpoczęcie transakcji SELECT TOP 5 * FROM Zatrudnieni WHERE Nazwisko LIKE 'B%' TRY --EXEC Nowy_pracownik 'BARTCZAK',99,'NOWAK',1200 --1. Błąd nazwiska --EXEC Nowy_pracownik 'BAN',99,'NOWAK',1200 --2. Błąd szefa --EXEC Nowy_pracownik 'BAN',99,'BRZEZINSKI',1200 --3. Błąd oddziału --EXEC Nowy_pracownik 'BAN',10,'BRZEZINSKI',1200 --4. Paremetry prawidłowe SELECT TOP 5 * FROM Zatrudnieni WHERE Nazwisko LIKE 'B%' TRY CATCH SELECT ERROR_NUMBER( ErrorNumber,ERROR_MESSAGE( ErrorMessage; CATCH -- Wycofanie Zadania - funkcje 5. Napisz funkcję PLACA_NETTO, która dla podanej płacy brutto (parametr i podanej stawki podatku wyliczy płacę netto. IF OBJECT_ID('Placa_netto','FN' IS NOT NULL DROP FUNCTION CREATE FUNCTION Placa_netto ( @Placa_Brutto FLOAT, @ProcentPodatku FLOAT RETURNS -- Test funkcji w miejsce wpisz numer indeksu SELECT [Labs\].Placa_netto (120,30 6. Napisz funkcję SILNIA, która dla danego n obliczy n! = 1 * 2 * * n. IF OBJECT_ID('Silnia','FN' IS NOT NULL DROP FUNCTION CREATE FUNCTION Silnia (@n INT RETURNS INT DECLARE @Wynik INT DECLARE @k INT SET @k=1 WHILE @k BAD210 Strona 5
IF @k=1 SET @Wynik ELSE SET @Wynik = SET @k = @k + RETURN(@Wynik -- Test funkcji w miejsce wpisz numer indeksu SELECT [Labs\].Silnia (1, [Labs\].Silnia (2, [Labs\].Silnia (3, [Labs\].Silnia (4, [Labs\].Silnia (5, [Labs\].Silnia (6 7. Napisz funkcję, która dla daty zatrudnienia pracownika wylicza staż pracy w latach. IF OBJECT_ID('Staz','FN' IS NOT NULL DROP FUNCTION CREATE FUNCTION Staz (@Data DATETIME RETURNS INT -- Test funkcji w miejsce wpisz numer indeksu SELECT Nazwisko, Zatrudniony, Staż=[Labs\].Staz(Zatrudniony FROM Zatrudnieni Zadania - Wyzwalacze 8. Utwórz wyzwalacz Szef na tabeli Zatrudnieni zamieniający wartość kodu szefa (kolumna Szef na NULL w przypadku usunięcia pracownika z tabeli Zatrudnieni, który jest szefem dla innych pracowników. -- Tworzenie wyzwalacza IF OBJECT_ID('dbo.Szef','TR' IS NOT NULL DROP TRIGGER dbo.szef CREATE TRIGGER dbo.szef ON FOR UPDATE SET Szef = NULL WHERE Szef IN (SELECT ID FROM -- Skrypt testujący TRAN SELECT * FROM Zatrudnieni WHERE Szef IS NULL OR Szef IN ('110', '120' DELETE FROM Zatrudnieni WHERE ID='120'; BAD210 Strona 6
SELECT * FROM Zatrudnieni WHERE Szef IS NULL OR Szef IN ('110', '120' 9. Utwórz tabelę Historia o kolumnach ID, ID_Prac, Placa_pod, Stanowisko, Oddzial, Sysdate. Napisz wyzwalacz Trace na tabeli Zatrudnieni, który po każdej modyfikacji (wstawiania, zmiany, usuwania płacy podstawowej, stanowiska lub oddziału będzie wpisywał wartości historyczne do tabeli Historia. -- Zakładanie tabeli Historia IF OBJECT_ID('dbo.Historia','U' IS NOT NULL DROP TABLE dbo.historia CREATE TABLE dbo.historia ( ID INT IDENTITY(1,1, Typ VARCHAR(1, ID_Prac INT, Placa_pod FLOAT, Stanowisko VARCHAR(20, ID_Oddz VARCHAR(20, Sysdate DATETIME DEFAULT GETDATE( ; -- Tworzenie wyzwalacza IF OBJECT_ID('dbo.Trace','TR' IS NOT NULL DROP dbo.trace CREATE TRIGGER dbo.trace ON FOR INSERT, UPDATE, DELETE IF EXISTS (SELECT ID FROM inserted -- Stare wartości IF EXISTS (SELECT ID FROM deleted INSERT INTO Historia (ID_Prac,Typ,Placa_pod,Stanowisko,ID_Oddz SELECT ID,'S', Placa_pod, Stanowisko, ID_Oddz FROM -- Nowe wartości INSERT INTO (ID_Prac,Typ,Placa_pod,Stanowisko,ID_Oddz SELECT ID, 'N', Placa_pod, Stanowisko, ID_Oddz FROM ELSE -- Usuwane wartości IF EXISTS (SELECT ID FROM deleted INSERT INTO (ID_Prac,Typ,Placa_pod,Stanowisko,ID_Oddz SELECT ID,'U', Placa_pod, Stanowisko, ID_Oddz FROM BAD210 Strona 7
-- Skrypt testujący TRAN SELECT * FROM Historia; UPDATE Zatrudnieni SET Placa_pod = 3800 WHERE Nazwisko = 'KOWAL'; DELETE FROM Zatrudnieni WHERE Nazwisko = 'BOGULA'; SELECT * FROM Historia; BAD210 Strona 8