Labb LIVE Exempelkod från föreläsningen Plushögskolan Frågeutveckling inom MSSQL - SU14
Här kommer exempelkoden jag använde under föreläsningen Exemplen Constraints... 2 Transactions... 4 Views... 5 Functions... 6 Stored Procedure... 7 Triggers... 8 1
Constraints Först skapar vi databasen och väljer att den ska användas Create database Movies go use movies Sedan skapar vi tabeller Först filmtabellen (den skapas först då den innehåller Primary Key som vi ska hänvisa till från den andra tabellen) create table Movies ( movieid int identity(1,1) primary key not null, name varchar(100) unique, released_year int default datepart(year,getdate()) ) MovieID är Primary key med räknare från 1 och upp. Då den är primary key får den automatiskt unique och not null constraints. Name är också unik, så att inte samma film matas in två gånger. Released year får standardvärde, detta år, för att ha något värde överhuvudtaget. create table Characters ( charid int identity(1,1) primary key not null, name varchar(100), fk_movieid int, FOREIGN KEY(fk_movieID) references Movies(MovieID) ) CharID är primary key och får alla primary key standards Name kontrolleras inte Fk_MovieID, prefixet talar om att det är en forreign key och namnet därefter talar om fältet vi hänvisar till. Efter det har vi själva relationen definierad. Characters.fk_movieID = Movies.movieID Då vi skapar den kopplingen så måste alla Characters som får en fk_movieid som inte är null, se till att ha ett matchande värde i Movies.movieID. För att slippa skriva en massa importerar vi nu alla filmer som finns i HayaoMiyazaki tabellen. insert into Movies (name) select distinct Movie from [HayaoMiyazaki].[dbo].CoolCharacters Sedan importerar vi alla personer till Characterlistan insert into Characters(name) select distinct Name from [HayaoMiyazaki].[dbo].CoolCharacters 2
Vill vi nu koppla ihop båda tabellerna utan att behöva göra det för hand, kan vi använda en liten script för det DECLARE @Char varchar(50)='how' Declare @movieid int = ( SELECT TOP 1 Movies.movieID FROM HayaoMiyazaki.dbo.CoolCharacters INNER JOIN Movies ON HayaoMiyazaki.dbo.CoolCharacters.Movie = Movies.name WHERE (HayaoMiyazaki.dbo.CoolCharacters.Name LIKE '%' + @Char + '%') ) UPDATE SET WHERE SELECT FROM Characters fk_movieid = @movieid (name LIKE '%' + @Char + '%') Characters.name, Movies.name AS Movie Characters LEFT OUTER JOIN Movies ON Characters.fk_movieID = Movies.movieID I @char skriver vi in namnet på karaktären vi söker, sedan jämför vi det namnet med originaltabellens lista, hittar filmen där och hämtar ID från filmen och lagrar det i @movieid. @movieid används sedan för att uppdatera tabellen med Characters. Och slutligen gör vi en Select för att se kopplingarna. Rörigt eller hur Vi återkommer till detta senare Nu har vi i alla fall en massa karaktärer kopplade till filmer Vad händer om vi skapar en ny karaktär och sparar den med ett okänt IDnummer? INSERT INTO Characters(Name, fk_movieid) values('ponyo',15); På grund av Constrainten vi har så kommer database att klaga och vägra spara INSERT satsen. Alltså måste vi skapa filmen insert into Movies (name) values ('Ponyo on the cliff by the sea'); Nu finns inte filmen I den gamla listan, så vi får söka upp IDt själva i vår Movies tabell select * from movies; När du väl hittat ditt ID kan du göra om inmatningen INSERT INTO Characters(Name, fk_movieid) values('ponyo',{idt du fick}); Eller så kan du vara lat och skriva INSERT INTO Characters(Name, fk_movieid) values('ponyo', (Select top 1 movieid from Movies order by movieid DESC)); I vilket fall har du nu matat in din film med rätt info, så dina Constraints har inte klagat. 3
Transactions Nu ska vi prova att vara destruktiva med skydd av Transactions Vi börjar med att skapa en transaction och radera alla karaktärer ur Characters, detta för att constrainten inte ska bråka med raderingen av alla filmer. Begin transaction Killer; delete from Characters; delete from movies; select * from movies; rollback transaction Killer; select * from movies; select * from Characters; När vi kör koden får vi frame en tom lista från Movies, men efter rollbacken får vi tillbaka allt. Även våra karaktärer. Egentligen behöver vi inte döpa Transaction till något, men det är bra att göra det speciellt om man kör flera transactions i varandra. Begin transaction Multikiller Save transaction KillChars delete from Characters; save transaction KillMovies delete from movies; rollback transaction Killmovies; select * from movies; select * from Characters; rollback transaction Här startar vi en Transaction kallad Multikiller Sedan startar vi en ny kallad KillCharacters, den raderar alla karaktärer ur tabellen. Efter detta startar vi upp ännu en transaction kallad KillMovies, och raderar alla filmer, vilket är något vi ångrar så vi återvänder till save -punkten för KillMovies. I den finns alla filmer kvar med inte karaktärerna. Så när vi kör en Select på karaktärerna får vi en tom databas. Slutligen rollbackar vi allt och därmed har inget ont hänt 4
Views Minns du koden vi skrev för att se listan på filmkaraktärer och filmer, nåväl, vi ska kolla på den igen. SELECT FROM Characters.name, Movies.name AS Movie Characters LEFT OUTER JOIN Movies ON Characters.fk_movieID = Movies.movieID Varenda gång vi vill se listan måste vi skriva om koden, sant, men inte om man skapar en vy. Vyn är lätt att skapa. CREATE VIEW FilmKaraktärer AS SELECT Characters.name, Movies.name AS Movie FROM Characters LEFT OUTER JOIN Movies ON Characters.fk_movieID = Movies.movieID Så var det klart! En View är en sökning, vill man slippa göra om den kan man spara det som en vy. 5
Functions Funktioner är en sort för sig. I dagens demo hade vi en funktion som räknade en ut dagarna till jul. Funktioner är lika enkla att skapa som Vyer. Man anger CREATE FUNCTION {Funktionsnamn} ({@Parameter Typ},{@Parameter Typ}) AS { --Massor med SQLkod return; } Såhär såg det ut i demot. CREATE FUNCTION DaysToXmas () RETURNS INT as begin DECLARE @ThisYear int =Year(getdate()); DECLARE @DaysTillXmas int = datediff(dd,getdate(),datefromparts(@thisyear,12,25)); if (@DaysTillXmas<0) SET @DaysTillXmas = datediff(dd,getdate(),datefromparts(@thisyear+1,12,25)); return @DaysTillXmas; end Och så testar vi det Select dbo.daystoxmas(); Functionerna kan innehålla vilken som helst SQL-kod du vill slippa upprepa, exempelvis en function som Räknar ut värden som den hämtar från en tabell. Eller som denna som söker upp en karaktär i databasen HayaoMiyazaki CREATE function [dbo].[findmovie] (@Character varchar(50)) returns varchar(50) as BEGIN return (SELECT TOP 1 Movie from CoolCharacters WHERE Name LIKE '%'+@Character+'%') END Och vi testar select dbo.findmovie('mei'); Hur fint som helst! 6
Stored Procedure Vi skapade en Stored Procedure med samma funktionalitet som funktionen som sökte upp filmer. create procedure HayaoMiyazaki.dbo.FindMovie @Character varchar(50) AS Select Movie from coolcharacters where Name LIKE '%'+@Character+'%' return go och testade use HayaoMiyazaki; findmovie 'Totoro' Stored procedures kan innehålla mer kod, som ifsatser, while loops mm. Var inte rädd för att experimentera med dem. Men kom ihåg att alltid använda Transactions! 7
Triggers Vi börjar med att skapa en testdatabas och förser den med lite data create database Balans go use Balans create table Konto ( id int identity, Insättning money, Uttag money, Saldo Money ) insert into konto (Insättning, Uttag) values (100,50), (44,10); Vi kollar nu vad som kommit in select * from konto order by id desc; Trevligt, nu behöver vi bara att den ska uppdatera Saldo när man kör en insert eller update Skrämmande kod, men det ser ut att fungera create trigger RäknaSaldo on Konto for insert as BEGIN update konto set saldo = konto.insättning - konto.uttag from inserted where konto.id = inserted.id END GO Alla triggers behöver inte vara så skrämmande, men det finns tack o lov redskap att använda när man hamnar därinne. Tabellerna Inserted och deleted förser med den informationen som behövs (till motsats av vad som stod i dagens slideshow) Mer läsning om det finns här: http://www.dotnet-tricks.com/tutorial/sqlserver/7ot8250912- Inserted,-Deleted-Logical-table-in-SQL-Server.html Det var allt för dagens live-labbande. 8