Labb LABB 14 Live demo exempeldata Plushögskolan Frågeutveckling inom MSSQL - SU14
Detta är exemplen som jag använde under dagens lektion Innehåll Lite grundläggande påminnelser... 2 Läsa in XML till en temporär tabell... 3 En snyggare tabell output... 5 Från tabell till XML (FOR XML)... 6 For XML Auto... 6 For XML Raw... 6 For XML Raw, Elements... 6 FOR XML PATH... 7 XML Query... 8 XML Exist... 9 XML Modify... 10 XML Modify Delete... 11 Disclaimer: Årtalet på filmernas utgivningsår stämmer inte, det är satt till standard:2015 <PageNumber> 1</PageNumber>
Lite grundläggande påminnelser Uttryck /Data Betydelse Sökväg till ett element i XMLkoden <xmlkod> <data Attribut="Min Attribut"></data> </xmlkod> /@Attribut Sökväg till ett attribut i XMLkoden <xmlkod> <data Attribut="Min Attribut"></data> </xmlkod> //Info och /xmlkod/data/info Det är en hel sökväg fram till ett specifikt attribut eller element <xmlkod> <data Attribut="Min Attribut"> <info>massor med info</info> </data> </xmlkod>. Nuvarande position i XML strukturen.. Förälderelementets position / Rotelementets position Tänk på att XML är case sensitive både i koder och noder, du kan alltså ha noder som heter <Data> <data> <DaTa> och alla kommer att behandlas som olika fristående element. <PageNumber> 2</PageNumber>
Läsa in XML till en temporär tabell DECLARE @DocHandle int; DECLARE @doc varchar(max)= ' <Movies> <Movie Name="My neighbour Totoro"> <Characters Name="Totoro" /> <Characters Name="Mei" /> <Characters Name="Satsuki" /> <Year>1988</Year> </Movie> <Movie Name="Ponyo on the Cliff by the Sea"> <Characters Name="Ponyo" /> <Characters Name="Brunhilde" /> <Year>2008</Year> </Movie> </Movies>'; exec sp_xml_preparedocument @DocHandle OUTPUT, @doc; select * from OPENXML(@DocHandle,'/Movies') exec sp_xml_removedocument @DocHandle Det första vi gör är att deklarera två variabler. En för att hålla reda på den temporära tabellens Handle, eller Minnesplats-ID och en för att handskas med själva XMLkoden. Sedan tilldelar vi XMLKodsvariabeln hela XMLKoden. Det är en sträng, men kan lika gärna vara XMLdata. Faktum är att om vi inte vill använda VarChar(max) så kan vi använda typen XML. Det går precis lika bra Nu tar vi i med hårdhandskarna, vi anropar en store procedure som ska returnera Dokumentets handle som output, precis som Out prefixen i C#. Nu kan vi använda vår Handle för att göra en vanlig SQL-Sökning i XMLKoden, den har nämligen tolkats om till en tabell. Yep, det vi får ut är skrämmande! Man kan faktiskt ana strukturen där, Parentid är en Foreign key till id. Nodetypen talar om ifall det är ett element eller en attribut, localname talar om vad elementer heter, datatypen, prefixen och namespacet har inte angetts så det är null, Prev talar om vilket element som var före i listan. 3 <PageNumber> 3</PageNumber>
Kör koden igen men ändra Select satsen till select * from OPENXML(@docID,'/Movies') order by id, parentid Så kommer du nog att kunna se strukturen lite bättre. Jämför du siffrornas ordning med original-xmlkoden så kan du se mönstret. Glöm inte att frigöra din Handle när du är klar med tabellen! <PageNumber> 4</PageNumber>
En snyggare tabell output Vi kör fortfarande med samma kod som innan, men nu ändrar vi select satsen igen select * from OPENXML(@docID,'//Characters') with ( Name varchar(100) '@Name', Movie varchar(100) '../@Name', Released int '../Year' ) // betyder att den ska söka igenom strukturen tills den hittar ett element som matchar, det kunde lika gärna ha stått /Movies/Movie/Characters. Låt dig inte luras till att tro att koden är bortkommenterad! När vi använder with talar vi om vilka element och attribut vi vill ha. De presenteras i form av en helt vanlig SQL-tabell. Här skulle vi kunna stoppa lektionen. Då XMLkoden har omvandlats till en temporär tabell kan vi använda den tabellen för att importera de värden vi behöver i vår tabell. Resultatet blir snyggt och prydligt <PageNumber> 5</PageNumber>
Från tabell till XML (FOR XML) use Movies; select Movies.name as Movie, Characters.name as [Character], Movies.released_year from Movies inner join Characters On Movies.movieID = Characters.fk_movieID order by Movies.name, Characters.name for XML AUTO Man kan omvandla en vanlig tabell till XML, och resultaten kan skilja drastiskt. Tänk på att använda en XML-output som matchar din XML-input, annars blir din kod inte kompatibel med sig själv. For XML Auto Resultatet blir en snygg kod <Movies Movie="Howl's Moving Castle" released_year="2015"> <Characters Character="Howl" /> <Characters Character="Sophie" /> </Movies> <Movies Movie="Kiki's Delivery Service" released_year="2015"> <Characters Character="Kiki" /> </Movies> Fler exempel finns här http://www.codeproject.com/articles/54584/controlling-the-xmloutput-when-using-the-for-xml For XML Raw Ändrar man SQL satsens for XML kod till for XML RAW ('Miyazaki') får vi följande resultat <Miyazaki Movie="Howl's Moving Castle" Character="Howl" released_year="2015" /> <Miyazaki Movie="Howl's Moving Castle" Character="Sophie" released_year="2015" /> <Miyazaki Movie="Kiki's Delivery Service" Character="Kiki" released_year="2015" /> <Miyazaki Movie="My neighbour Totoro" Character="Mei" released_year="2015" /> Innanför parentesen anger man vad varje rads element ska heta, standardvärde är row For XML Raw, Elements Vill man inte ha datan som attribut kan man välja att få det som element genom att lägga till ELEMENTS i SELECT FOR satsen: for XML RAW ('Miyazaki'), ELEMENTS Och resultatet blir följande <Miyazaki> <Movie>Howl's Moving Castle</Movie> <Character>Howl</Character> <released_year>2015</released_year> </Miyazaki> <Miyazaki> <Movie>Howl's Moving Castle</Movie> <Character>Sophie</Character> <released_year>2015</released_year> </Miyazaki> <Miyazaki> <PageNumber> 6</PageNumber>
<Movie>Kiki's Delivery Service</Movie> <Character>Kiki</Character> <released_year>2015</released_year> </Miyazaki> FOR XML PATH Detta ger mer eller eller mindre samma resultat som FOR XML RAW, ELEMENTS Ändra i din SELECT SATS FOR till FOR XML PATH ('Miyazaki') <Miyazaki> <Movie>Howl's Moving Castle</Movie> <Character>Howl</Character> <released_year>2015</released_year> </Miyazaki> <Miyazaki> <Movie>Howl's Moving Castle</Movie> <Character>Sophie</Character> <released_year>2015</released_year> </Miyazaki> <Miyazaki> <Movie>Kiki's Delivery Service</Movie> <Character>Kiki</Character> <released_year>2015</released_year> </Miyazaki> <PageNumber> 7</PageNumber>
XML Query För kommande tester ska vi skapa en tabell som ska spara vår XML kod, hittils har vi bara kört med den temporära tabellen use Movies; CREATE TABLE XMLMovies ( ID int primary key identity(1,1); MovieInfo XML ) GO Och nu kan vi importera datan dit DECLARE @XMLData xml; SET @XMLData=( select Movies.name as Movie, Characters.name as [Character], Movies.released_year from Movies inner join Characters On Movies.movieID = Characters.fk_movieID order by Movies.name, Characters.name for XML PATH); INSERT INTO XMLMovies (MovieInfo) Values(@XMLData); Koden skapar en variable I vilken hela XMLkoden läses in. XMLkoden genereras av en helt vanlig SQLquery som kör XML output for XML PATH. Nu när vi har datan lagrad i database kan vi göra sökningar utan att behöva återskapa vår tabell. select movieinfo from xmlmovies; Select MovieInfo.query('row/Movie') as Movie from XmlMovies Nu kan vi söka i XMLkoden med funktionen query. I query anger man sökvägen man vill ha fram. I detta fall row/movie <PageNumber> 8</PageNumber>
XML Exist XML Exist använder man för att kolla om ett värde finns eller om den matchar givna parametrar. Exist är en booleansk jämförelsefunktion som returnerar 1 eller 0. Den använder följande sökmetoder Uttryck Matematiskt Talspråk Funktion Eq = Equal Lika med funktion Ne!= Not Equal Inte lika med Lt < Less than Mindre än Gt > Greater than Större än Le <= Less or equal Mindre än eller lika med Ge => Greater or equal Större eller lika med För att använda funktionen måste man göra en SET (jag vet, det låter knas, men så är det) Den här koden kommer att söka efter filmer med karaktären Kiki. [. = värde ] betyder jämför värdet på elementet/attributen med det givna värdet DECLARE @Data xml; Select @Data=MovieInfo.query('Movies') from XmlMovies WHERE MovieInfo.exist('//@Character[. = "Kiki"]')=1; Select @Data; <PageNumber> 9</PageNumber>
XML Modify Om vi nu ska söka upp filmen Kiki s delivery service och översätta titeln till Kikis expressbud så får vi söka såhär DECLARE @Data xml; Select @Data=MovieInfo.query('Movies') from XmlMovies WHERE MovieInfo.exist('Movies/Characters/@Character[. = "Kiki"]')=1; När vi fårr fram informationen kan vi modifier det. Här utgår vi ifrån att vi fått bara ett träff(!) SET @Data.modify('replace value of (Movies/@Movie)[1] with "Kikis expressbud!"'); Select @Data; Nu är titeln ändrad, men om vi söker i tabellen kommer den forfarande att ha samma titel. Select MovieInfo.query('Movies') from XmlMovies WHERE MovieInfo.exist('Movies/Characters/@Character[. = "Kiki"]')=1; Detta sker på grund av att vi ändrat i vår variabel men inte i tabellen. Vill vi ändra tabellen får vi spara variabelvärdet först. För att kunna modifiera dataraden i tabellen måste vi ha någon slags ID att identifiera raden med. Enklast gör vi det såhär. DECLARE @Data xml; DECLARE @ID int; Select from WHERE @ID=ID, @Data=MovieInfo.query('Movies') XmlMovies MovieInfo.exist('Movies/Characters/@Character[. = "Kiki"]')=1; Sedan modifierar vi vår data SET @Data.modify('replace value of (Movies/@Movie)[1] with "Kikis expressbud!"'); Och slutligen ska vi spara det UPDATE SET WHERE XMLMovies MovieInfo=@Data ID=@ID; En enkel sökning i databasen nu bekräftar att den är sparad Select FROM WHERE MovieInfo.query('Movies') XmlMovies MovieInfo.exist('//@Character[. = "Kiki"]')=1; <PageNumber> 10</PageNumber>
XML Modify Delete Man kan använda samma sökning som i föregående sida och lägga till, detta kommer att göra att filmen tas bort ur listan. Den kommer dock inte att tas bort från tabellen förrän vi stoppar in @Data i tabellens rad som vi hämtade innan. SET @Data.modify('delete (/Movies)[1]'); Select @Data; Vill du spara ändringarna får du göra på samma sätt som med Modify exemplet, alltså ta rade på ID och updatera din tabell. Det var det <PageNumber> 11</PageNumber>