1. Code
  2. Mobile Development
  3. Android Development

Android SDK: Verwalten der Sqlite3-Datenbanken mit mehreren Tabellen

Scroll to top

German (Deutsch) translation by Katharina Grigorovich-Nevolina (you can also view the original English article)

Dieses Tutorial bietet eine interaktive Anwendung zum Erstellen und Verwalten von Datenbanken mit mehreren Tabellen für Android-Geräte. Es werden Datenbanknavigations- und Suchfunktionen sowie ein Popup zur Eingabe von Abfragen bereitgestellt, in dem Freiformabfragen ausgeführt und die Ergebnisse in einem Bildlauffeld angezeigt werden.

SQLite3 ist eine kompakte Transaktionsdatenbank mit geringem Speicher- und Speicherbedarf. Es wird häufig in mobilen Betriebssystemen wie Android, iPhone usw. verwendet. Es ist jetzt eine vollständig relationale Datenbank mit Fremdschlüsselunterstützung.

Eine Datenbank enthält normalerweise eine oder mehrere Tabellen. Die Tabellen dienen zum Speichern von Daten vier Typen: Integer, Real, String und Blob (binäre oder große Daten). Es gibt viele nette Tutorials zum Erstellen und Verwalten von Einzeltabellendatenbanken.

Eine ausführliche Beschreibung der Grundlagen der Tabellenerstellung finden Sie unter:

Da Android keinen Datenbankschnittstellen-Manager bereitstellt, lernen wir in diesen Tutorials effiziente Möglichkeiten zum Erstellen und Verwalten einer Datenbank mit nur einer Tabelle.

Im Wesentlichen sind die folgenden Schritte erforderlich:

1. Zuerst wird eine Database Helper-Klasse definiert, die von der SQLiteOpenHelper-Klasse erweitert wird. Das hilft beim Erstellen oder Öffnen einer Datenbank, beim Aktualisieren der Datenbank und beim Definieren von Tabellen, Spalten, Indizes, Triggern und Ansichten für eine Datenbank.

2.Mit dieser Hilfsklasse wird eine Datenbankadapterklasse entworfen, in der die grundlegenden CRUD-Datenbankverwaltungstools (Erstellen, Lesen, Aktualisieren und Löschen) programmiert sind.

3. Die SQL-Abfragen werden zum Verwalten von CRUD-Operationen verwendet. Der Datenabruf erfolgt mit Cursorn.
Die realen Datenbanken haben normalerweise mehr als eine Tabelle. Das führt zu Problemen bei der Erstellung und Verwaltung der Tabellen.

Das folgende Verfahren ist das Standardverfahren für ein Datenbankdesign mit mehreren Tabellen:

1. Da die Datenbank auf dem Android-Gerät bereitgestellt ist, kann sie nach ihrer Erstellung nicht mehr auf dem Telefongerät geändert werden. Die Änderungen erfordern manuelle Eingriffe wie das Abrufen der Datenbank vom Gerät, das Ändern mit Sqlite3 Manager und das erneute Bereitstellen auf dem Telefongerät.

2. Alle Tabellen müssen gleichzeitig in der Funktion onCreate der Datenbank-Hilfsklasse erstellt werden. Diese Funktion wird aufgerufen, wenn die Datenbankadapterklasse instanziiert wird. Jede Tabelle muss über eine eigene Erstellungs-SQL verfügen. Der Befehl execSql muss für jede Tabelle separat ausgeführt werden.

3. Wie verwalten wir diese Tabellen? Benötigen wir separate Adapter für jede Tabelle? Wenn jemand eine große Anzahl von Tabellen hat, wäre die Adapterüberlastung enorm. Leider befassen sich die meisten veröffentlichten Tutorials mit diesem Ansatz.

Wäre es nicht schön, die Datenbank und viele Tabellen mit einer einzigen Adapterschnittstelle zu erstellen und zu verwalten? Ja wird es sein. In diesem Tutorial wird ein solches Datenbankdesign mit zwei grafischen Android-Benutzeroberflächen (GUI) unter Verwendung von zwei Android-Aktivitätsklassen beschrieben. Die erste Aktivität, StartIntMulti, bietet eine einfache Benutzereingabeschnittstelle, über die die Datenbank- und Tabellenentwürfe eingegeben werden. Nach Abschluss der Eingabe bietet die zweite Aktivität, ManageIntMulti, die grundlegende CRUD-Verwaltung und eine Tabellennavigationsfunktion mit Suche mit nur einer Datenbankadapterklasse. Es wird auch ein Abfrageeingabefeld entworfen, in dem jede Abfrage unabhängig von der ausgewählten Tabellenschnittstelle ausgeführt werden kann.

In diesem Tutorial wird davon ausgegangen, dass der Leser mit der Erstellung und Verwaltung von Einzeltabellendatenbanken vertraut ist. Wir werden einem schönen Beispiel einer Multi-Table-Datenbank von Android Sqlit folgen.

Beginnen wir mit der ersten unten gezeigten GUI-Oberfläche.

GUI Interface

Das ist eine Schnittstelle, die für einen interaktiven Datenbankersteller erforderlich ist. Die Datenverwaltung erfolgt über eine DataAttrib-Klasse. Diese Klasse hat verschiedene Mitglieder, die beim Speichern und Abrufen der Eingabedaten helfen.

Die ersten beiden Bearbeitungsfelder erfordern die Eingabe von Datenbanknamen und Versionsnummern. Geben Sie ChessDb als Datenbanknamen und 1 als Versionsnummer ein. Klicken Sie auf die Schaltfläche Neue Datenbank, um die Eingaben zu speichern. Die Eingabe wird über die Funktionen setDbName und setDbVersion der Klasse gespeichert. Das Klassenmitglied setDbStatus speichert den Status "neu" oder "alt" der Datenbank (verwenden Sie für eine zuvor erstellte Datenbank die Schaltflächen Alte Datenbank und Datenbank starten, um zur nächsten Aktivität zu gelangen).

Die nächsten drei Bearbeitungsfelder übernehmen die Eingabe des Tabellennamens. Geben Sie für unsere Zwecke "Spieler" als Tabellennamen ein. Die Tabellennamen werden in einem Array tbl_Names[] gespeichert, und die Anzahl der Tabellen wird in setNumTables aufgezeichnet.

Die nächsten beiden Bearbeitungsfelder übernehmen die Eingaben für Feldname und Feldtyp. Das erste Feld jeder Tabelle ist "_id", ein ganzzahliger Typ. Es ist der Primärschlüssel und wird automatisch inkrementiert. Es wird automatisch programmiert und muss nicht eingegeben werden. Geben Sie im Feldnamen "fname" als Eingabe für den Feldnamen und "text" als Eingabe für den Typ ein (verwenden Sie nicht "" in den Eingabefeldern). Das "nicht null" ist im Programm selbst voreingestellt. Der Feldname und der Feldtyp werden in den zweidimensionalen Arrays Col_Names[][] und Col_Types gespeichert. Die Anzahl der Spalten wird im Array Ncols[] aufgezeichnet.

Klicken Sie auf die Schaltfläche "Feld hinzufügen", um die Eingabe zu speichern. Dies löscht das Feld Feldname. Geben Sie nun im gleichen Eingabefeld für den Feldnamen die zweite Feldvariable "lname" ein. Stellen Sie sicher, dass das Eingabefeld gelöscht ist, bevor Sie neue Eingaben eingeben. Die Eingabe Typ ist "text". Klicken Sie erneut auf die Schaltfläche Feld hinzufügen. Da wir mit der ersten Tabellendefinition fertig sind, klicken wir auf die Schaltfläche Tabelle erstellen. Stellen Sie sicher, dass Sie diese Taste nicht drücken, es sei denn, alle Felder wurden definiert.

Table DesignTable DesignTable Design

Die "Kaskadenlöschung" sollte in der letzten Zeile "bei Kaskade löschen" sein. Beachten Sie, dass ich die Tabellenstruktur von der in der Referenz definierten geändert habe, um die Tabellen konsistent zu halten. Wenn Sie einen zusammengesetzten Primärindex wünschen, können Sie diese Tabelle über die GUI des Abfrageherstellers in der nächsten Oberfläche erstellen.

Das ist alles für jetzt. Wenn Sie mehr Tabellen haben, können Sie auf die gleiche Weise eingeben. Die Programmierung hinter den Kulissen ist eine Standard-Java-Programmierung für Android-Anwendungen. Die Daten werden in der DatabaseAttrib-Klasse gespeichert. Schauen Sie sich die Struktur dieser Klasse an. Es besteht aus einer grundlegenden Getter- und Setter-Funktion für die oben beschriebenen Eingänge. Klicken Sie auf die Schaltfläche Datenbank starten, um zur nächsten Ebene der Datenbankverwaltung zu gelangen.

Die folgende GUI zeigt die Aktivitätsklasse für die Datenbankverwaltung:

GUI

Lassen Sie uns den allgemeinen Prozess der Datenbankverwaltungsaktivität untersuchen. Wenn der Benutzer die neue oder alte Datenbank startet, erhält diese Aktivität, ManageIntMulti, alle Informationen zu den Tabellen, Feldnamen und Typen von der DataAttrib-Klasse. Ganz oben auf der GUI befindet sich neben den TextBox-Beschriftungen eine Spinner-Steueroberfläche für die Tabellenauswahl. Das Spinner-Steuerelement wird mit den Namen dieser Tabellen gefüllt. Es handelt sich um eine Optionsfeldsteuerung, bei der jeweils nur ein Element ausgewählt werden kann. Das ausgewählte Element ist ein bestimmter Tabellenname.

Als Nächstes wird der Datenbankadapter tableAdapter nur einmal instanziiert. Die Funktion onCreate erstellt alle Tabellen in der Datenbank. Sehen Sie sich das Codefragment für diesen Prozess an.

1
if (DATABASE_STATUS == "new" )
2
			{
3
4
			String str1 ="";
5
			 for ( int i= 0; i<Num_Tbls; i++)
6
			 {
7
				 String SuppString = " ";
8
				 str1 = " ";
9
			    for ( int j=0; j< Num_Cols[i]-1; j++)
10
		        {
11
12
		   	       SuppString =  SuppString + Var_Names[i][j] + " " + Var_Types[i][j] +" not null"+", ";
13
14
		        }
15
		         str1 = "create table " +
16
		                  Tbl_Names[i] +
17
		       " (" +
18
		           ID_FIELD + " integer primary key autoincrement, " +
19
				   SuppString + Var_Names[i][Num_Cols[i]-1] + " " + Var_Types[i][Num_Cols[i]-1] + " not null" +
20
		       ");";
21
22
			     db.execSQL(str1);
23
			     Log.d(DATABASE_NAME, "onCreate: " + Tbl_Names[i]);
24
25
			   }
26
27
			}

Das ist eine der Möglichkeiten, wie der Algorithmus zur Erstellung mehrerer Tabellen implementiert werden kann. Jede Tabelle, jeder Feldname und jeder Feldtyp wird zu einer SQL-Zeichenfolge zusammengefasst. Das ID-Feld ist "_id" und wird für jede Tabelle programmiert (nicht eingegeben). Nach dem Zusammenstellen der SQL-Zeichenfolge führt db.execSql(str1) die Tabelle SQL aus und erstellt sie. Theoretisch sollte diese Methode der interaktiven Eingabe die Anzahl der Tabellen oder Felder nicht einschränken. Das DataAttrib legt jedoch eine Dimensionsbeschränkung von [10] für eindimensionale und [10][10] für zweidimensionale Arrays fest. Sie kann auf einen beliebigen Wert erhöht werden. Für die Funktion zur Überprüfung von Duplikaten sind zusätzlich zum Feld _id mindestens zwei Tabellenspalten erforderlich.

Als Nächstes werden die Duplikate in einer Tabelle mit einer SQL-Anweisung durchsucht, die die ersten beiden Felder in den Suchkriterien verwendet. Die bedingten Feldnamen werden mithilfe der PRAGMA-Abfrage in der aktuellen Tabelle vom Cursor abgerufen. Die Verwendung der PRAGMA-Abfrage erleichtert die Verwendung mehrerer Datenbankadapter. Der Datenbankcursor wird mit dem Prozess db.rawQuery (…) generiert. Das typische Such-SQL sollte den Benutzern der ACCESS-Datenbank wie folgt bekannt sein:

1
   String chkVar ="( " + xtbl + "." + colName[1] +"||' '||"+ xtbl + "." + colName[2]+" )";
2
   String sql =     "SELECT "  +
3
	                 chkVar + " AS Var1, "  +
4
	      " count" + chkVar + " " + " as NumDupes" +
5
	      " FROM " + xtbl +" Group by " + chkVar + " having ((count" + chkVar + ")>1);";

Dabei ist xtbl die aktuell ausgewählte Tabelle. Wenn Duplikate gefunden werden, wird der Benutzer mit Toast-Warnungen benachrichtigt und die Ergebnisse werden in der Bildlaufansicht unter der EditBox mit der Bezeichnung "Abfrage" gedruckt. Die doppelten Daten werden nicht automatisch entfernt. Mit Run Query und einer CRUD-Schnittstelle kann dies effizienter durchgeführt werden.

Als nächstes werden alle Komponenten einer Ansicht eingerichtet und die Rückruffunktionen für die Tastenlistener definiert.

Es gibt viele Möglichkeiten, Daten in eine Tabelle einzugeben. Hier verwenden wir vier EditBox-Eingabefelder (F1, Fld2, Fld3 und Fld 4) für die Datenverarbeitung. F1 ist für das Feld _id reserviert und der Benutzer interagiert nur beim Löschen oder Aktualisieren einer Tabelle damit. Die anderen Felder sind für Feldnamen wie fname und lname in der Players-Tabelle. Wenn Sie mehr als drei Eingaben haben, können Sie das Feld Abfrage verwenden, um eine beliebige CRUD-Operation auszuführen. Geben wir "Bobby" in Fld2 und "Fisher" in Fld3 ein (niemals ", da sie hier nur zur Verdeutlichung verwendet werden). Klicken Sie auf die Schaltfläche Erstellen. Dadurch werden die Daten in der Datenbanktabelle gespeichert. Sie können so viele Daten eingeben, wie Sie möchten. Lassen Sie uns dieses Dateneinfügungsschema etwas genauer untersuchen. Das Folgende ist das zugehörige Code-Snippet.

1
private void createData()
2
  {
3
  	try
4
  	{
5
6
  	 	 String xtbl = input.getText().toString();
7
  	 	 String [] x = getInputStr();
8
  	 	 Cursor cursor = getPragma();
9
10
  		 int noCols = cursor.getColumnCount();
11
12
  		 int k = 0;
13
  	     String [] colName = new String[noCols];
14
15
  	     ContentValues values = new ContentValues();
16
17
  	 	  while (cursor.moveToNext()) {
18
  	      for (int i=0; i<cursor.getColumnCount(); i++)
19
  	      {
20
  	         colName[i] = cursor.getString(i);
21
22
  	      }
23
  	       if (k > 0 )
24
  	    	 values.put(colName[1], x[k]);
25
26
  	       k++;
27
  	 	 }
28
29
 	     db1.insert(xtbl, null, values);
30
 	     cursor.close();
31
  	}
32
  	catch (Exception e)
33
  	{
34
  		Log.e("sql Error", e.toString());
35
  		e.printStackTrace();
36
  	}
37
  }

Dies ist ein typisches Dateneinfügungsschema. Wie üblich gibt es viele andere Möglichkeiten, die Daten in eine Tabelle einzufügen. Hier sind xtbl die Daten, die in der Drehfeldsteuerung ausgewählt wurden. Die Feldnamen stammen von der Variablen x[] aus den Eingaben. Wir rufen PRAGMA auf, um die Feldnamen dieser bestimmten Tabelle als colName[] abzurufen. Wir verwenden eine ContentValues-Klasse, um die Eingaben den richtigen Spaltennamen zuzuweisen. Das db1.insert(…) fügt schließlich die Eingaben in die Datenbank ein.

Die anderen CRUD-Operationen, nämlich Lesen, Aktualisieren und Löschen, folgen einer ähnlichen Logik mit entsprechenden SQL-Anweisungen.

Die Schaltfläche Lesen erfordert die Eingabe der _id-Nummer. Geben Sie die _id-Nummer in das Feld F1 ein und drücken Sie diese Taste, um die Daten in anderen Feldern anzuzeigen.

Die Schaltfläche Aktualisieren funktioniert auch mit der Eingabe _id. Holen Sie sich zuerst die richtigen Daten mit einem Lesevorgang und geben Sie dann Änderungen in andere Eingabefelder ein. Klicken Sie auf die Schaltfläche Aktualisieren, um Ihre Änderungen zu speichern.

Die Schaltfläche Löschen funktioniert auch mit dem Feld _id. Geben Sie die _id-Nummer ein und drücken Sie die Entfernen-Taste. Die Daten werden ohne Vorwarnung dauerhaft gelöscht, es sei denn, einige Fremdschlüsseleinschränkungen werden verletzt.

Die Schaltflächenzeilen first, rev, next, last und search werden zum Navigieren in den Daten in der Tabelle verwendet. Fügen Sie zunächst so viele Einträge wie Sie möchten in die Tabelle ein. Mit diesen Schaltflächen können Sie Ihre Eingabedaten durchsuchen. Wenn Sie viele Einträge haben, wäre es sehr frustrierend, einen Datensatz zu finden. Die Suchtaste ist für diesen Zweck praktisch. Alle Suchvorgänge werden anhand der Kombination der ersten beiden in Fld2 und Fld3 eingegebenen Felder durchgeführt. Die Suche nimmt teilweise Eingaben vor und unterscheidet nicht zwischen Groß- und Kleinschreibung.

Die Datenbanknavigation verwendet die Feldnamen aus PRAGMA und der richtigen db.query, um alle Tabellendaten in einem Cursor abzurufen. Die Navigation erfolgt mit den Funktionen cursor.moveToFirst(), cursor.moveToLast(), cursor.setPosition(), cursor, getPosition, cursor.moveToPrevious() und cursor.moveToNext().

Die Suchvorgänge verwenden die Option LIKE. Es wurde berichtet, dass diese Art von Kriterien die Suche in großen Tabellen verlangsamt. Die Android Developer-Website bietet eine alternative schnelle Suchmethode. Um den Suchprozess unabhängig von Groß- und Kleinschreibung zu machen und Teileingaben vorzunehmen, wird die folgende Bedingung aus der Funktion searchData() verwendet.

1
 String str2 = "lower(" + y[1] + ")" + " like "+ "lower("+ "'%"+xsearch[0].trim()+"%'"+ ")" +" and " +
2
  	 	               "lower(" + y[2] + ")" + " like "+ "lower("+ "'%"+xsearch[1].trim()+"%'"+ ")";

Dabei ist y[] der Feldname und xsearch[] die Suchzeichenfolge. Das ist ein sehr nützliches Schema. Viele andere effiziente Suchalgorithmen werden auch bei der Datenbanksuche verwendet. Ein Index wird auch für die beiden Suchfelder generiert, um den binären Suchprozess zu beschleunigen.

Als nächstes ist die Abfrage ausführen ein sehr nützliches Werkzeug zum Ausführen von Abfragen. Wenn Sie auf die Abfrage ausführen-Schaltfläche klicken, wird ein benutzerdefiniertes Popup-Dialogfeld angezeigt. Dieser Ansatz eignet sich aufgrund der begrenzten Anzeigefläche auf dem Emulator gut für die Eingabe langer Abfragen. Geben Sie eine Abfrage ein, die einige Daten zurückgibt, z. B. "Select * from any_table;" und drücken Sie die Go-Taste. Die zurückgegebenen Daten werden in einem Bildlauffeld unter der Schaltfläche "Abfrage ausführen" angezeigt. Die Abfragen können für jede Tabelle ausgeführt werden, unabhängig von der aktuell ausgewählten im Spinner-Steuerelement. Mit dieser Option können Sie alles tun, was Sie mit der Datenbank tun möchten. Verlassen Sie den Bildschirm für die Abfrageeingabe, indem Sie auf die Beenden-Schaltfläche klicken.

Mit der Zurück-Schaltfläche kehren Sie zur Dateneingabeaktivität zurück. Sie können nur aktive Datenbanken von hier aus neu starten. Für neue müssen Sie beenden und sich erneut bei der Anwendung anmelden.

Eine sehr nützliche SQL-Anweisung für eine effiziente Programmierung ist PRAGMA mit folgender Struktur:

PRAGMA table_info (table_name);

Dies erzeugt eine Ausgabe mit fünf Spalten. Die zweite Spalte ist der Name der Feldvariablen und die dritte Spalte ist der Feldtyp.

Sie können die Tabellenauswahl ändern und Ihre Datenbankverwaltung nach Belieben durchführen. Alle diese Vorgänge für alle Tabellen werden mit nur einer Datenbankadapterklasse ausgeführt.

Wenn eine vorhandene Datenbank ausgewählt ist, werden der Datenbankname und die Version von der Eingabe-GUI an die Navigations-GUI übergeben. Die Datenbank wird in der Funktion onCreate des Adapters verbunden, indem der Pfad zur vorhandenen Datenbank angegeben wird. Stellen Sie sicher, dass Sie den Paketnamen im Pfad an Ihren Standort anpassen. Die Tabellennamen werden mit folgendem SQL abgerufen:

1
"SELECT name FROM "+ " sqlite_master WHERE type='table' " +
2
	      " AND name NOT LIKE 'sqlite_%'  AND name NOT LIKE 'android%' UNION ALL" +
3
	      " SELECT name FROM sqlite_temp_master WHERE type='table' " +
4
	      " ORDER BY 1;";

dabei ist 'tabelle' eine interne Variable der Schemadatenbank. Der Rest der Datenbankverwaltung ist der gleiche wie im neuen Datenbankfall.

Die Abfrageeingabedatenbank weist eine Reihe von Zeichenbeschränkungen in der EditBox auf. Der kritische Test zum Ausführen der Abfragesteuerung wird im folgenden Artikel mit der folgenden SQL ausgeführt.

1
 sql =     "SELECT "  +
2
    " Players.fname||' '|| Players.lname AS PlayerName, "  +
3
    " SUM((Games.weight*GameResults.score)) AS TotalWeightedScore " +
4
    " FROM GameResults " +
5
   " JOIN Players " +
6
   "         ON (GameResults.playerid=Players._id) "  +
7
   " JOIN Games  "   +
8
    "        ON (GameResults.gameid=Games._id) "  +
9
   " GROUP BY GameResults.playerid " +
10
   " ORDER BY TotalWeightedScore DESC;";

Das ist eine Java-Version von SQL. Um in das Abfragefeld zu gelangen, müssen Sie die Interpunktionen " und + entfernen. Verwenden Sie den Artikel aus dem Artikel, auf den verwiesen wird. Auch diese lange Abfrage kann mit der Popup-Abfrageeingabe ausgeführt werden. Stellen Sie sicher, dass Sie die Abfrage korrekt eingeben, da sie sonst abstürzen kann oder nichts passiert.

Mit der Beenden-Schaltfläche verlassen Sie diese Anwendung. Wenn Sie neue Tabellen, Indizes und Trigger erstellt haben, müssen Sie das aktuelle Setup beenden und erneut eingeben, um die neuen Inhalte anzuzeigen.

Möglicherweise haben Sie bemerkt, dass der Datenbankadapter nur einmal instanziiert wurde. Die Verwendung von PRAGMA und durchdachtes Programmieren verringert die Notwendigkeit mehrerer umständlicher Adapter. Einige von Ihnen verwenden möglicherweise ähnliche Programme in Ihrer täglichen Arbeit, aber für den Rest von uns sollte dies ein neues und effizientes Programm sein!