Christophe Bovigny

Werbung
Christophe Bovigny
Baris Ulucinar
Fribourg, le 20 décembre 2004
Übung 5
Prozeduren, Triggers und Transaktionen
1.
CREATE VIEW v_wine_produzent (wine, producer)
As
SELECT wine.name, producer.name
FROM wine, producer
WHERE wine.producer_id = producer.id
2.
CREATE VIEW
v_degustator_rating (degustator, wine, taste)
As
SELECT
degustator.name, wine.name, taste.rating
FROM degustator, wine, taste
WHERE
degustator.id = taste.degustator_id and
wine.id = taste.wine_id
3.
CREATE PROCEDURE
change_name @degustator_name_old varchar (30),
@degustator_name_new varchar (30)
AS
IF EXISTS
(SELECT name
FROM degustator
WHERE name = @degustator_name_old)
BEGIN
UPDATE
degustator
SET
name = @degustator_name_new
FROM degustator
WHERE
name = @degustator_name_old
PRINT
'Der Degustator '+'@degustator_name_old'+' wurde in
'+'@degustator_name_new'+'umbenannt.'
END
ELSE
PRINT 'Der Degustator '+'degustator_name_old'+' existiert nicht.'
4.
CREATE PROCEDURE
wine_rating @wine_name varchar (30)
AS
IF EXISTS
(SELECT rating
FROM taste,wine
WHERE taste.wine_id = wine.id and wine.name = @wine_name)
BEGIN
DECLARE
@avg varchar(99), @category varchar(30)
SET
@avg =(SELECT avg(rating)
FROM taste,wine
WHERE taste.wine_id = wine.id
and wine.name = @wine_name)
SET
@category =(SELECT category
FROM wine
WHERE wine.name = @wine_name)
PRINT 'LE VIN: '+@wine_name+', sa categorie: '+@category+
', son evaluation '+@avg
END
ELSE
PRINT 'LE VIN '+@wine_name+' na pas ete evalue'
5.
CREATE TRIGGER ref_integ_foreign
ON mitarbeiter
FOR UPDATE, INSERT
AS
DECLARE @new_inserted integer;
SELECT @new_inserted =(SELECT abt_nr
FROM inserted);
IF EXISTS (SELECT abt_nr
FROM abteilung
WHERE @new_inserted = abt_nr)
BEGIN
PRINT 'Ok, go on ...';
COMMIT TRANSACTION;
END
ELSE
BEGIN
PRINT 'Referential integrity on -abteilung- not respected ...';
PRINT 'Transaction canceled !';
ROLLBACK TRANSACTION
END
-- ref integrity control for the primary key of abteilung
CREATE TRIGGER ref_integ_prim_ab
ON abteilung
FOR UPDATE, INSERT
AS
DECLARE @new_inserted integer;
SELECT @new_inserted =(SELECT abt_nr
FROM inserted);
IF (SELECT COUNT(abt_nr)
FROM abteilung
WHERE @new_inserted = abt_nr) > 1
BEGIN
PRINT 'Referential integrity on primary key not respected ... (ABT)';
PRINT 'Transaction cancelled !';
ROLLBACK TRANSACTION;
END
ELSE
BEGIN
PRINT 'Oki doki, go on ... (PK)(ABT)';
COMMIT TRANSACTION;
END
6.
TRIGGER :
CREATE TRIGGER journalise
ON Mitarbeiter
FOR INSERT, UPDATE, DELETE
AS
DECLARE @rollbacked int
DECLARE @affected_id int
SET @rollbacked = 0
-- check if entry salary < 100000
IF EXISTS (SELECT MA_Gehalt FROM inserted)
BEGIN
IF NOT EXISTS (SELECT MA_Gehalt FROM deleted)
BEGIN
DECLARE @salary_check integer
SELECT @salary_check = (SELECT MA_Gehalt FROM inserted)
-- we are in an INSERT operation, now check if it is < 100000
IF (@salary_check > 100000)
BEGIN
PRINT 'Salary is too high to start...'
ROLLBACK TRANSACTION
SET @rollbacked = 1
END
END
END
IF UPDATE(Mitarbeiter_Einstellungsdatum)
BEGIN
IF EXISTS (SELECT Mitarbeiter_Einstellungsdatum FROM deleted)
BEGIN
PRINT 'Not possible to change this date.'
ROLLBACK TRANSACTION
END
END
IF UPDATE(MA_GEHALT)
BEGIN
DECLARE @new_salary integer
DECLARE @old_salary integer
SELECT @old_salary = (SELECT MA_Gehalt FROM deleted)
SELECT @new_salary = (SELECT MA_Gehalt FROM inserted)
IF(@new_salary > @old_salary * 1.06)
BEGIN
PRINT 'Salary can not raised from more than 6%.'
ROLLBACK TRANSACTION
END
END
-- Journalize only if the transaction occured (i.e. rollbacked != 1)
IF (@rollbacked != 1)
BEGIN
SELECT @affected_id = (SELECT Mitarbeiter_id FROM INSERTED)
IF UPDATE(Mitarbeiter_Name)
BEGIN
DECLARE @old1 char (20)
SELECT @old1 = (SELECT Mitarbeiter_Name FROM INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
Mitarbeiter_Name) VALUES (user_name(), getdate(), @affected_id, @old1)
END
IF UPDATE(Mitarbeiter_Vorname)
BEGIN
DECLARE @old2 char (20)
SELECT @old2 = (SELECT Mitarbeiter_Vorname FROM
INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
Mitarbeiter_Vorname) VALUES (user_name(), getdate(), @affected_id, @old2)
END
IF UPDATE(Mitarbeiter_Geburtstag)
BEGIN
DECLARE @old3 datetime
SELECT @old3 = (SELECT Mitarbeiter_Geburtstag FROM
INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
Mitarbeiter_Geburtstag) VALUES (user_name(), getdate(), @affected_id, @old3)
END
IF UPDATE(Mitarbeiter_Einstellungsdatum)
BEGIN
DECLARE @old4 datetime
SELECT @old4 = (SELECT Mitarbeiter_Einstellungsdatum FROM
INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
Mitarbeiter_Einstellungsdatum) VALUES (user_name(), getdate(), @affected_id,
@old4)
END
IF UPDATE(MA_Adresse)
BEGIN
DECLARE @old5 varchar (50)
SELECT @old5 = (SELECT MA_Adresse FROM INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
MA_Adresse) VALUES (user_name(), getdate(), @affected_id, @old5)
END
IF UPDATE(MA_PLZ)
BEGIN
DECLARE @old6 varchar (10)
SELECT @old6 = (SELECT MA_PLZ FROM INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
MA_PLZ) VALUES (user_name(), getdate(), @affected_id, @old6)
END
IF UPDATE(MA_Ort)
BEGIN
DECLARE @old7 varchar (50)
SELECT @old7 = (SELECT MA_Ort FROM INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
MA_Ort) VALUES (user_name(), getdate(), @affected_id, @old7)
END
IF UPDATE(MA_GEHALT)
BEGIN
DECLARE @old8 int
SELECT @old8 = (SELECT MA_GEHALT FROM INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
MA_GEHALT) VALUES (user_name(), getdate(), @affected_id, @old8)
END
IF UPDATE(Bemerkung)
BEGIN
DECLARE @old9 varchar (100)
SELECT @old9 = (SELECT Bemerkung FROM INSERTED)
-- insert into log table
INSERT INTO Mitarbeiter_log (Benutzer, Zeit, Affected_id,
Bemerkung) VALUES (user_name(), getdate(), @affected_id, @old9)
END
PRINT 'Operations logged in Mitarbeiter_log'
END
TABLES:
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Mitarbeiter]')
and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Mitarbeiter]
GO
if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[Mitarbeiter_log]') and OBJECTPROPERTY(id, N'IsUserTable')
= 1)
drop table [dbo].[Mitarbeiter_log]
GO
CREATE TABLE [dbo].[Mitarbeiter] (
[Mitarbeiter_ID] [int] IDENTITY (40, 1) NOT NULL ,
[Mitarbeiter_Name] [char] (20) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL ,
[Mitarbeiter_Vorname] [char] (20) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL ,
[Mitarbeiter_Geburtstag] [datetime] NULL ,
[Mitarbeiter_Einstellungsdatum] [datetime] NULL ,
[MA_Adresse] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[MA_PLZ] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[MA_Ort] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[MA_Gehalt] [int] NULL ,
[Bemerkung] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Mitarbeiter_log] (
[log_id] [int] IDENTITY (1, 1) NOT NULL ,
[affected_id] [int] NOT NULL ,
[Benutzer] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS
NOT NULL ,
[Zeit] [datetime] NOT NULL ,
[Mitarbeiter_Einstellungsdatum] [datetime] NULL ,
[Mitarbeiter_Name] [char] (20) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL ,
[Mitarbeiter_Vorname] [char] (20) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL ,
[Mitarbeiter_Geburtstag] [datetime] NULL ,
[MA_Adresse] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[MA_PLZ] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[MA_Ort] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[MA_Gehalt] [int] NULL ,
[Bemerkung] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL
) ON [PRIMARY]
GO
7.
DEADLOCKS
Transaction 1
BEGIN Transaction
UPDATE seller
SET country = ‘Swiss’
WHERE seller.id = 10
UPDATE sell
SET sell.price = 56
WHERE sell.seller_id = 5
COMMIT Transaction
Transaction 2
BEGIN Transaction
UPDATE sell
SET sell.quantity = 15
WHERE sell.seller_id = 10
UPDATE seller
SET name = ‘Boy’
WHERE seller.id = 5
COMMIT Transaction
Note : Lancer les 2 transactions exactement en même temps !
Une solution pour éviter un deadlock dans un tel cas est de rendre les transactions plus
atomiques, c'est-à-dire de les rendre plus petites :
Transaction 1
BEGIN Transaction
UPDATE seller
SET country = ‘Swiss’
WHERE seller.id = 10
COMMIT Transaction
Transaction 1’
BEGIN Transaction
UPDATE sell
SET sell.price = 56
WHERE sell.seller_id = 5
COMMIT Transaction
Transaction 2
BEGIN Transaction
UPDATE sell
SET sell.quantity = 15
WHERE sell.seller_id = 10
COMMIT Transaction
Tansaction 2’
BEGIN Transaction
UPDATE seller
SET name = ‘Boy’
WHERE seller.id = 5
COMMIT Transaction
De cette manière, la transaction 1 libère la ligne seller.id = 10 directement après avoir effectué
l’opération d’update. Ceci étant, la transaction 2 pourra l’employer.
Les deux opérations de la transaction 1 ne sont pas liées, il n’y a donc pas de raison de les
effectuer dans une seule et unique transaction.
Cette solution fonctionne tant que (et uniquement lorsque) les opérations au sein d’une
transaction sont atomisables et indépendantes.
KETTENBLOCKIERUNG
Transaction 1
BEGIN Transaction
UPDATE seller
SET country = ‘German’
WHERE seller.id = 10
UPDATE sell
SET sell.price = 56
WHERE sell.seller_id = 5
… (operations prenant un certain temps)
COMMIT Transaction
Transaction 2
BEGIN Transaction
UPDATE sell
SET sell.price = 100
WHERE sell.seller_id = 5
UPDATE seller
SET country = ‘Swiss’
WHERE seller.id = 10
COMMIT Transaction
Transaction 3
BEGIN Transaction
UPDATE wine
SET name = ‘Côtes du rhônes’
WHERE wine.id = 9
UPDATE sell
SET sell.price = 200
WHERE sell.seller_id = 5
COMMIT Transaction
Herunterladen