SQLite Crash Course för Android Developers

Android-applikationer kan lagra applikationsdata i SQLite-databaser. I denna handledning lär du dig hur SQLite-databaser är utformade och manipulerade.

Här börjar vi med att designa och använda en enkel SQLite-databas för att hantera schackturneringsresultat. Denna handledning är avsedd som en kort översikt över hur SQLite databaser fungerar. Denna kunskap kommer sedan att användas i framtida utvecklingshandledning för att genomföra databasdrivna Android-applikationer.

Komma igång

Android-applikationer kan skapa och manipulera sina egna privata SQLite relationsdatabaser. Utvecklare kan också inspektera och modifiera databaser på en given Android-emulator eller -enhet med hjälp av kommandoradsverktyget sqlite3 som tillhandahålls som en del av Android SDK-verktyget heter Android Debug Bridge (adb).

I den här handledningen antar vi att du har en viss förståelse för relationsdatabaser, teoretiskt, men behöver lite en uppfriskningskurs innan du använder dem i dina Android-applikationer. Denna speciella handledning kräver inga verktyg. Det är mer en teoretisk övning.

Om du planerar att utveckla Android-applikationer som bygger på SQLite-databaser måste du installera de verktyg som behövs för Android-utveckling, t.ex. Android SDK och Eclipse IDE. Kolla in de många andra användbara Android-handledningarna som finns här på Mobiletuts + för att hjälpa dig att arbeta med dessa uppgifter.

Vad är SQLite?

SQLite är en lättviktsrelationell databasmotor. SQLite är snabb och har ett litet fotavtryck vilket gör det perfekt för Android-enheter. I stället för de tunga servern baserade databaser som Oracle och Microsoft SQL Server lagras varje SQLite-databas inom en enda fil på disken. Android-applikationer kan välja att lagra privatprogramdata i en SQLite-databas.

Obs! Om du är bekant med SQL, är SQLite väldigt lätt att hämta. SQLite är i princip en avvecklad SQL-databasmotor för inbyggda enheter. För information om SQLite och dess funktioner, funktionalitet och begränsningar, se SQLite online dokumentation.

En snabb granskning av databaser

En databas är helt enkelt ett strukturerat sätt att lagra data på ett bestående sätt. Data lagras i tabeller. En tabell har kolumner med olika datatyper. Varje rad i en tabell representerar en datapost. Det kan hända att du tycker om att tänka på ett bord som ett Excel-kalkylblad. För ett objektorienterat programmeringsperspektiv representerar varje tabell i en databas ofta ett objekt (representerat av en klass). Varje tabellkolumn representerar ett klassattribut. Varje post i en tabell representerar en specifik förekomst av det objektet.

Låt oss titta på ett snabbt exempel. Låt oss säga att du har en företagsdatabas med ett bord som heter Employee. Medarbetare tabellen kan ha fem typade kolumner: EmployeeID (nummer), FirstName (sträng), LastName (sträng), Titel (sträng) och Lön (nummer). Du kan sedan lägga till en post i databasen för en anställd som heter John Doe och en separat post för en anställd som heter Anne Droid.

Data i en databas är avsedd att inspekteras och manipuleras. Data i ett bord kan vara:

  • Tillagt (med hjälp av FÖRA IN kommando)
  • Ändrad (med hjälp av UPPDATERING kommando)
  • Ta bort (med hjälp av RADERA kommando)

Du kan söka efter specifika uppgifter i en databas med hjälp av det som kallas en fråga. En fråga (med SELECT-kommandot) kan innebära ett bord eller flera tabeller. För att skapa en fråga måste du ange tabellerna, datakolumnerna och datavärdena av intresse med hjälp av SQL-kommandospråk. Varje SQL-kommando avslutas med en semikolon (;).

Schackturneringsdatabasen

Det bästa sättet att verkligen förstå hur SQLite-databaser fungerar är att arbeta genom ett enkelt exempel, så låt oss göra det. Låt oss låtsas att vi har en applikation som håller koll på spelarens poäng från en ledig schackturnering. Spelarens poäng spelas in och sedan, i slutet av en serie matchningar, bestäms vinnaren. Varje spelares totala turneringspoäng beräknas utifrån deras prestanda på:

  • Fyra uppvärmningsvärmer (vikt: 10% av den totala poängen)
  • En semifinal (vikt: 25% av den totala poängen)
  • En final (vikt: 35% av den totala poängen)

Obs! För turneringen kan spelarens poäng baseras på en formel som faktorer i den tid det tog för att vinna spelet och typen och antalet bitar kvar på styrelsen i slutet av spelet. På så sätt får en stark spelare en hög poäng för att förlora några kraftfulla bitar och vinna spelet snabbt. Kanske är stil och attityd inkluderad av domarna för att uppmuntra roligt, lättspel. Hur poäng beräknas är verkligen inte viktigt för hur vi definierar vår databas; Vi lagrar dem bara i databasen. För enkelhet kommer vi att anta att poängen är baserade på en skala från 0-100.

Designa databasschemat

Ett databasschema är helt enkelt definitionen av databasens struktur i form av tabeller, datakolonner och liknande. Schemat för vår turneringsdatabas är ganska enkelt:

TournamentScores databasschema har tre tabeller:

  • Spelarens tabell innehåller spelarinformation.
  • Speltabellen innehåller information om varje spel och hur mycket det räknas mot spelarens totala turneringsresultat.
  • TableResults-tabellen innehåller alla spelares spelresultat.

SQLite3 har stöd för följande vanliga datatyper för kolumner:

  • HELTAL (signerade heltal)
  • VERKLIG (flytpunktsvärden)
  • TEXT (UTF-8 eller UTF-16-sträng, kodad med databaskodning)
  • KLICK (data bit)

När du har bestämt vilka kolumner som behövs för varje tabell, är du redo att skapa några tabeller i ditt databasschema.

Arbeta med tabeller

Låt oss börja med att skapa spelarens tabell. Denna tabell kräver ett unikt spelarens id för att referera till varje spelare. Vi kan göra detta till den primära nyckeln (för att unikt identifiera en post i den här tabellen) och ange dess autoincrement-attribut. Autoincrement innebär att varje gång en ny spelarrekord läggs till kommer rekordet att få ett nytt unikt spelar-ID. Vi vill också lagra för- och efternamn för varje spelare - inga tillåtna nollar.
Här kan vi använda CREATE TABLE SQL-satsen för att generera tabellen Spelare:

CREATE TABLE Players (id INTEGER PRIMARY KEY AUTOINCREMENT, fname TEXT NOT NULL, lname TEXT NOT NULL); 

Spelbordet är mycket lika. Vi behöver ett unikt spel id för att referera till varje spel. Vi vill också ha ett vänligt namn för varje spel och ett viktvärde för hur mycket spelet spelar mot spelarens slutliga turneringsresultat (i procent). Här är SQL-satsen för att skapa spelbordet:

CREATE TABLE Games (id INTEGER PRIMARY KEY AUTOINCREMENT, spelnamn TEXT, vikt REAL DEFAULT .10 CHECK (vikt<=1)); 

Du kan också ta bort tabeller med DROP TABLE-satsen. Om du till exempel vill ta bort spellistan använder du följande SQL-kommando:

DROP TABLE Spel; 

Populära tabeller med dataposter

Innan vi fortsätter, lägger vi till några data i dessa tabeller. För att lägga till en post i spelarens tabell måste du ange kolumnnamnen och värdena i ordning. Till exempel använder följande SQL-formulär INSERT-kommandot för att lägga till en post för schackspelaren Bobby Fisher:

INSERT till spelare (fname, lname) VALUES ('Bobby', 'Fisher'); 

Medan vi är där lägger vi till ytterligare två spelare: Bart Simpson (en väldigt ynklig schackspelare) och Garry Kasparov (kanske den bästa schackspelaren någonsin). Samtidigt behöver vi lägga till en massa poster i spelbordet. Först lägger vi till semifinal, vilket motsvarar 25 procent av spelarens turneringspoäng:

INSERT till spel (spelnamn, vikt) värden ("semifinal", .25); 

Sedan lägger vi till ett par värmeuppvärmningar, som använder standardvikten på 10 procent:

INSERT till spel (gamename) värden ('warm-up heat 1'); 

Slutligen lägger vi till ett finalvärde på 35 procent av det totala turneringsresultatet:

INSERT till spel (spelnamn, vikt) värden ("slutlig", .35); 

Fråga tabell för resultat med SELECT

Hur vet vi vilka data vi har lagt till i tabellen? Jo det är lätt. Vi frågar helt enkelt för alla rader i ett bord med ett SELECT-uttalande:

VÄLJ * FRÅN SPEL 

Detta returnerar alla poster i speltabellen:

id gamename weight ----- --------------- ------ 1 Semi-Final 0.25 2 Uppvärmningsvärme 1 0,1 3 Uppvärmningsvärme 2 0,1 4 Warm -up Värme 3 0,1 5 Uppvärmningsvärme 4 0,1 6 Slutlig 0,35 

Använda kolumnalaser och beräknade kolumner

Vi kan också skapa egna kolumner och alias dem. Till exempel kan vi skapa ett kolumnalias som heter PlayerName som är en beräknad kolumn: Det är spelarens för- och efternamn som sammanfogas med hjälp av || operatör, åtskilda av ett mellanslag:

VÄLJ fname || "|| lname AS PlayerName, id FROM Players; 

Den här frågan ger följande resultat:

Spelarensnamn id ------------ - Bobby Fisher 1 Bart Simpsen 2 Garry Kasparov 3 

Ändra data i tabeller

Barts (spelare id 2) efternamn är stavat felaktigt. För att uppdatera tabellen Spelare för att spegla rätt stavning kan du använda kommandot UPDATE:

UPPDATERA Spelare SET lname = "Simpson" WHERE playerid = 2; 

Du kan radera rader från ett bord med funktionen DELETE. Till exempel, för att radera den post som vi just uppdaterat:

DELETE från spelare WHERE playerid = 2; 

Du kan radera alla rader i en tabell genom att inte ange WHERE-klausulen:

DELETE FROM Players; 

Använda utländska nycklar och kompositnycklar

Nu när vi har spelat upp våra Spelare och Spel, låt oss skapa TableResults-tabellen. Detta är ett mer komplicerat bord. TableResults-tabellen parar spelarens ids från spelarens tabell med spel-id från spelbordet och listar sedan poängen som spelaren tjänat för det specifika spelet. Kolumner, som länkar till andra tabeller på detta sätt, kallas ofta främmande nycklar. Vi vill ha unika spelarparametrar, så vi skapar en sammansatt huvudnyckel från spelarens och spelens främmande nycklar för att unikt identifiera en GameResults-post. Slutligen verkställer vi att poängen är heltal mellan 0 och 100.

CREATE TABLE GameResults (playerid INTEGER REFERENSER Spelare (id), gameid INTEGER REFERENSER Spel (id), poäng INTEGER CHECK (poäng<=100 AND score>= 0), PRIMARY KEY (playerid, gameid)); 

(Obs! SQLite tillämpar inte utländska nyckelbegränsningar, men du kan ställa in dem ändå och genomdriva begränsningarna genom att skapa utlösare.)
Nu är det dags att infoga några data i GameResults tabellen. Låt oss säga att Bobby Fisher (spelare id 1) fick ett poäng på 82 poäng på semifinalen (spel ID 1). Du kan använda följande SQL-kommando för att infoga den lämpliga posten i GameResults-tabellen:

INSERT i GameResults (playerid, gameid, score) värden (1,1,82); 

Låt oss nu anta att turneringen spelas och poängen läggs till i TableResults-tabellen. Bobby är en bra spelare, Bart är en hemsk spelare, och Garry spelar alltid ett perfekt spel. När posterna har lagts till i GameResults-tabellen kan vi utföra ett SELECT * -kommando för att lista alla poster i tabellen, eller vi kan explicit ange kolumner som följande:

VÄLJ playerid, gameid, värdera FROM GameResults; 

Här är resultaten från den här frågan:

playerid gameid score ---------- ---------- ----- 1 1 82 1 2 88 1 3 78 1 4 90 1 5 85 1 6 94 2 1 10 2 2 60 2 3 50 2 4 55 2 5 45 2 6 65 3 6 100 3 5 100 3 4 100 3 3 100 3 2 100 3 1 100 

Som du kan se är denna notering inte särskilt "mänsklig läsbar".

Fråga över flera tabeller med hjälp av JOIN

Skulle det inte vara mer användbart om namnen på spelarna och spelen visades istället för deras numeriska ids? Fråga och kombinera data i SELECT-satser hanteras ofta genom att utföra en JOIN med flera tabellkällor; Det finns olika typer av JOINS. När du arbetar med flera tabeller måste du ange vilken tabell som en kolumn tillhör (speciellt när kolumner heter samma, som med alla dessa olika id-kolumner). Du kan referera till kolumner med deras kolumnnamn eller deras tabellnamn, sedan en punkt (.) Och sedan kolumnnamnet.

Låt oss återuppta spelarens poäng igen, bara den här gången, inkludera spelets namn och spelarens namn. Också, vi begränsar våra resultat endast till poängen för finalen (game id 6):

SELECT Players.fname || "|| Players.lname AS PlayerName, Games.gamename, GameResults.score FRÅN GameResults GÅ MED SPILLARE PÅ (GameResults.playerid = Players.id) GÅ MED SPEL PÅ (GameResults.gameid = Games.id) Vart gameid = 6; 

vilket ger oss följande resultat (du kan lämna WHERE för att få alla spel):

Spelarnamn gamename poäng ------------------ -------------- ----- Bobby Fisher Final 94 Bart Simpson Final 65 Garry Kasparov Slutlig 100 

Genomföra mer komplexa frågor

Himlen är gränsen när det gäller de frågor du kan göra här. För vårt exempel är den viktigaste frågan den som berättar vem som vann turneringen.
Här är den sista frågan för att beräkna turneringens rankningar:

SELECT Players.fname || "|| Players.lname AS PlayerName, SUM ((Spel.vikt * GameResults.score)) AS TotalVågadScore FRÅN GameResults GÅ MED SPELARE PÅ (GameResults.playerid = Players.id) GÅ MED SPEL PÅ (GameResults.gameid = Spel.id) GRUPP AV GameResults.playerid BESTÄLL AV TotalVågadScore DESC; 

Denna fråga samlar information från flera olika tabeller med JOINs och beräknar turneringsresultaten på ett läsbart sätt. Så låt oss titta på vad den här frågan gör:

  • Varje spelares fullständiga namn visas som den första resultatkolumnen (beräknad från för- och efternamn)
  • Varje spelares turneringspoäng visas som andra resultatkolumnen (beräknad från de viktade poängen av alla spel som spelas av en given spelare)
  • Resultatlistan är listade i fallande ordning baserat på turneringsresultat (första plats, andra plats, etc.)

Resultaten från den här frågan visas nedan:

PlayerName TotalWeightedScore ------------------------- ----------------- Garry Kasparov 100.0 Bobby Fisher 87.5 Bart Simpson 46.25 

Slutsats

Detta avslutar vår undersökning av ett enkelt SQLite databas exempel: en schackturnatdatabas. Förhoppningsvis har du reacquainted dig med relationsdatabasskoncept som tabeller, poster och frågor och bekantat dig med många av de vanliga SQLite-kommandona. Slutligen har du gått igenom utformningen och användningen av en exempeldatabas. Nu när du har ett handtag om hur SQLite-databaser fungerar, är du redo att använda dem i dina Android-applikationer (ämnet för vår nästa handledning i den här serien).

Om Författarna

Mobila utvecklare Lauren Darcey och Shane Conder har medverkat flera böcker om Android-utveckling: en fördjupad programmeringsbok med titeln Android Wireless Application Development och Sams TeachYourself Android Application Development inom 24 timmar. När de inte skriver, spenderar de sin tid på att utveckla mobil mjukvara hos sina företag och tillhandahålla konsulttjänster. De kan nås via e-post till [email protected], via deras blogg på androidbook.blogspot.com, och på Twitter @ androidwireless.