{"id":1991,"date":"2021-03-27T17:28:41","date_gmt":"2021-03-27T17:28:41","guid":{"rendered":"https:\/\/www.art-events.de\/weblog\/?page_id=1991"},"modified":"2021-03-31T08:26:45","modified_gmt":"2021-03-31T08:26:45","slug":"android-programmieren-sql-lite-1","status":"publish","type":"page","link":"https:\/\/www.art-events.de\/weblog\/android-programmieren-sql-lite-1\/","title":{"rendered":"Android programmieren: SQL Lite 1"},"content":{"rendered":"<p>Mit SQLite liefert uns Android bereits einen vorinstallierten SQL Server f\u00fcr den wir nix mehr tun m\u00fcssen. Also nicht wie aus der PC Welt \u00fcblich: SQL installieren, User anlegen, Rechte definieren etc pp. Sondern unter Android: SQLite ist da. L\u00e4uft. Kann verwendet werden. Was auf einem Smartphone oder Tablett PC nat\u00fcrlich auch bedeutet: da greifen jetzt nicht mehrere Benutzer gleichzeitig auf die DB zu, sondern nur einer. Was uns aber SQLite unter Android bringt: Die unter SQLite gespeicherten Informationen werden immer sofort gespeichert und bleiben auch erhalten, wenn sich die Hardware ausschaltet oder die Anwendung beendet wird.<\/p>\n<p>In unserer Anwendung geht es daher nun darum, SQLite unter Android zu verwenden. Es soll eine Textdatei gelesen und in die SQL Datenbank geschrieben werden, es sollen Felder gelesen und Werte ge\u00e4ndert (Update) werden. Basis ist eine kleine Artikeldatei mit String-Feldern wie z.B. Artikelnummer, Artikeltext, Lagerort und Menge. Um keine Typkonvertierungen machen zu m\u00fcssen, sind alle Datenfelder als String ausgelegt, d.h. wenn Mengen in der Anwendung berechnet werden m\u00fcssen, sind Umwandlungen on String nach Integer \/ oder Double notwendig. Auf die Anwendung gehen wir nachstehend nicht ein, sondern konzentrieren uns auf den reinen SQL Teil der Software.<\/p>\n<p>Was wir tun m\u00fcssen:<\/p>\n<ul>\n<li>Klasse SQLHelper f\u00fcr die Anwendung erstellen<\/li>\n<li>Auf Package: Rechte Maustaste. ProjectDBSQLHelper<\/li>\n<li>Datenbase Namen und Grunddaten eintragen. Ebenso Funktion f\u00fcr CREATE TABLE und DROP<\/li>\n<li>Achtung: DB wird beim ersten Aufruf von DBHELPER erstellt und nicht mehr ge\u00e4ndert! Eine \u00c4nderung erfolgt nur, wenn die Versionsnummer erh\u00f6ht oder die Anwendung deinstalliert wird. (Unbedingt beachten, wenn ihr Felder \u00e4ndert \/ l\u00f6scht oder hinzuf\u00fcgt.)<\/li>\n<li>Beispiel findet sich nachfolgend.<\/li>\n<\/ul>\n<p>Die grundlegenden Definitionen und die Grundroutinen, die Ihr in jedem Fall ben\u00f6tigt folgen nachstehend. Es geht hier um eine DB mit vier String Felder und einem int Wert als Prim\u00e4rschl\u00fcssel, damit die Daten schnell lokalisiert werden k\u00f6nnen.<\/p>\n<blockquote>\n<pre>public class DonxieDBHelper extends SQLiteOpenHelper {\r\n\r\n    private static final String DATABASE_NAME = \"donxiestorage.db\";\r\n    private static final int DATABASE_VERSION = 1;\r\n    private static final String TABLE_NAME1 = \"data\";\r\n\r\n    private static final String TAG = \"SQLite\";\r\n\r\n    private static final String TABLE_MOD_CREATE = \"CREATE TABLE \" + TABLE_NAME1 + \" (AID INTEGER PRIMARY KEY, ARTNR TEXT, ARTTXT TEXT, QTY1 TEXT, LOCATION TEXT)\";\r\n    private String TABLE_MOD_DEL = \"DROP TABLE IF EXISTS \" + TABLE_NAME1;\r\n\r\n    public DonxieDBHelper(Context context) {\r\n        \/\/------------------------------------------------\r\n        \/\/------------------------------------------------\r\n        super(context, DATABASE_NAME, null, DATABASE_VERSION);\r\n        Log.d(TAG, \"DbHelper hat die Datenbank: \" + getDatabaseName() + \" erzeugt.\");\r\n    } \/\/\r\n\r\n\r\n    @Override\r\n    public void onCreate (SQLiteDatabase db) {\r\n        \/\/------------------------------------------------\r\n        \/\/------------------------------------------------\r\n\r\n        Log.i(TAG, \"MyDatabaseHelper.onCreate ... \");\r\n\r\n        try {\r\n            db.execSQL(TABLE_MOD_CREATE);\r\n            Log.d(TAG, \"On CreateOK\");\r\n        }\r\n        catch (Exception ex) {\r\n            Log.e(TAG, \"Fehler beim Anlegen der Tabelle: \" + ex.getMessage());\r\n        }\r\n    } \/\/\r\n\r\n    @Override\r\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r\n        \/\/------------------------------------------------\r\n        \/\/------------------------------------------------\r\n\r\n        Log.i(TAG, \"MyDatabaseHelper.onUpgrade ... \");\r\n\r\n        db.execSQL(TABLE_MOD_DEL);\r\n        onCreate(db);\r\n        Log.d(TAG, \"On CreateOK\");\r\n    } \/\/\r\n\r\n<\/pre>\n<\/blockquote>\n<hr \/>\n<p><strong>Datensatz einf\u00fcgen \/ INSERT<\/strong><\/p>\n<p>Neuen Datensatz in die SQLite DB einf\u00fcgen. Es werden alle Datenfelder als String \u00fcbergeben. Die Funktion ist als void definiert, ermittelt aber den Index des einzuf\u00fcgenden Satzes. Wer mag kann sie daher umbauen, dass sie diesen Index als Returnwert liefert oder halt -1, wenn der Schreibvorgang nicht durchgef\u00fchrt wurde.<\/p>\n<blockquote>\n<pre>public void insert (String artnr, String arttext, String menge, String location) {\r\n    \/\/------------------------------------------------\r\n    \/\/write 4 string felder into DB\r\n    \/\/------------------------------------------------\r\n\r\n    long rowid = -1;\r\n\r\n    \/\/Datenbank oeffnen\r\n    SQLiteDatabase db = getWritableDatabase();\r\n\r\n    ContentValues values = new ContentValues();\r\n    values.put(\"ARTNR\", artnr);\r\n    values.put(\"ARTTXT\", arttext);\r\n    values.put(\"QTY1\", menge);\r\n    values.put(\"LOCATION\", location);\r\n\r\n    rowid = db.insert(TABLE_NAME1, null, values);\r\n\r\n    \/\/Log.d(\"insert\", String.valueOf(rowid));\r\n} \/\/<\/pre>\n<\/blockquote>\n<hr \/>\n<p><strong>Datensatz Update<\/strong><\/p>\n<p>Einen Datensatz aktualisieren. Welcher Datensatz wird \u00fcber Feld index idx festgelegt. Es werden dann Stringfelder zum Aktualisieren \u00fcbergeben. Ein Return Wert ob es geklappt hat erfolgt nicht. (K\u00f6nnte man als boolean umbauen und den Erfolg an die Anwendung zur\u00fcckliefern.)<\/p>\n<blockquote>\n<pre>public void update (int idx, String artnr, String arttext, String menge, String location) {\r\n    \/\/------------------------------------------------\r\n    \/\/Update Record idx mit 4 string felder in DB\r\n    \/\/------------------------------------------------\r\n\r\n    String sSQL = \"UPDATE \" + TABLE_NAME1 + \" SET [ARTNR] = '\" + artnr + \"', [ARTTXT] = '\" + arttext + \"', [LOCATION] = '\" + location + \"', [QTY1] = '\" + menge + \"' WHERE AID=\" + idx;\r\n\r\n    Log.i(TAG, \"Update: \" + sSQL);\r\n\r\n    SQLiteDatabase db = getWritableDatabase();\r\n    db.execSQL(sSQL);\r\n} \/\/<\/pre>\n<\/blockquote>\n<hr \/>\n<p><strong>Datensatz lesen<\/strong><\/p>\n<p>Einen Datensatz aus der SQLite DB lesen. Als Suchbegriff wird die Artikelnummer verwendet. R\u00fcckgabe ist ein Objekt vom Typ Cursor, das in der Anwendung ausgewertet werden kann.<\/p>\n<blockquote>\n<pre>  public Cursor getItem (String myartnr) {\r\n        \/\/------------------------------------------------\r\n        \/\/Read item myartnr from DB. liefert werte in cursor zurueck\r\n        \/\/------------------------------------------------\r\n\r\n        \/\/ get readable database as we are not inserting anything\r\n        SQLiteDatabase db = this.getReadableDatabase();\r\n        Cursor cursor = db.rawQuery(\"SELECT * FROM \" + TABLE_NAME1 + \" WHERE ARTNR = '\" + myartnr + \"'\", null);\r\n\r\n\r\n\/*\r\n                Alternativ gehts auch \u00fcber Query Abfrage im folgenden Format:\r\n                Cursor cursor = db.query(Note.TABLE_NAME,\r\n                new String[]{Note.COLUMN_ID, Note.COLUMN_NOTE, Note.COLUMN_TIMESTAMP},\r\n                Note.COLUMN_ID + \"=?\",\r\n                new String[]{String.valueOf(id)}, null, null, null, null);\r\n\r\n *\/\r\n\r\n        if (cursor != null)\r\n            cursor.moveToFirst();\r\n\r\n        \/\/cursor.close();\r\n        return cursor;\r\n    } \/\/<\/pre>\n<\/blockquote>\n<p>&nbsp;<\/p>\n<hr \/>\n<p><strong>Anzahl der Datens\u00e4tze z\u00e4hlen<\/strong><\/p>\n<p>Die Anzahl der Datens\u00e4tze in der DB wird ermittelt und von der Routine als int Wert zur\u00fcck geliefert.<\/p>\n<blockquote>\n<pre>public int CountItems () {\r\n    \/\/------------------------------------------------\r\n    \/\/ Anzahl Records in DB zaehlen. Liefert Anazhl als int\r\n    \/\/------------------------------------------------\r\n\r\n    SQLiteDatabase db = getWritableDatabase();\r\n    Cursor cursor = db.rawQuery(\"SELECT * FROM \" + TABLE_NAME1, null);\r\n    int i = cursor.getCount();\r\n    cursor.close();\r\n    return (i);\r\n} \/\/<\/pre>\n<\/blockquote>\n<hr \/>\n<p><strong>Datenbank Inhalt l\u00f6schen<\/strong><\/p>\n<p>Alle Daten der SQLite DB in den M\u00fcll treten. Am Ende sind alle Daten weg und k\u00f6nnen neu eingef\u00fcgt werden. Die Struktur der DB wird nicht ver\u00e4ndert.<\/p>\n<blockquote>\n<pre>public void deletedata () {\r\n    \/\/------------------------------------------------\r\n    \/\/------------------------------------------------\r\n\r\n    SQLiteDatabase db = getWritableDatabase();\r\n    db.execSQL(\"delete from \"+ TABLE_NAME1);\r\n    Log.i(TAG, \"Delete SQL Items\");\r\n} \/\/<\/pre>\n<\/blockquote>\n<hr \/>\n<p><strong>Datenbank l\u00f6schen<\/strong><\/p>\n<p>Die SQLite Tabelle entfernen. Die ist hinterher allerdings v\u00f6llig futsch und muss neu angelegt werden, bevor sie verwendet und mit Daten gef\u00fcllt werden kann. Also eigentlich keine wirklich sinnvolle Sache &#8211; aber der Vollst\u00e4ndigkeit halber bei mir dabei:<\/p>\n<blockquote>\n<pre>public void deletetable () {\r\n    \/\/------------------------------------------------\r\n    \/\/------------------------------------------------\r\n\r\n    SQLiteDatabase db = getWritableDatabase();\r\n    db.execSQL(TABLE_MOD_DEL);\r\n    Log.i(TAG, \"Delete Table ... \");\r\n} \/\/<\/pre>\n<\/blockquote>\n<hr \/>\n<p><strong>Datenbank exportieren<\/strong><\/p>\n<p>Hier wollen wir die gesamte SQLite DB in eine TXT Datei exportieren:<\/p>\n<blockquote>\n<pre>public void exportDB(String toFile) {\r\n    \/\/------------------------------------------------\r\n    \/\/Exportiert DB nach Datei.\r\n    \/\/------------------------------------------------\r\n\r\n    SQLiteDatabase db = this.getReadableDatabase();\r\n\r\n    File dcimDir = null;\r\n    if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.KITKAT) {\r\n        dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);\r\n    }\r\n\r\n    File myFile = new File (dcimDir, toFile);\r\n\r\n\r\n    try\r\n    {\r\n        myFile.createNewFile();\r\n\r\n        FileWriter fw = new FileWriter(myFile, false);\r\n\r\n        Cursor cursor = db.rawQuery(\"SELECT * FROM \" + TABLE_NAME1,null);\r\n        \/\/csvWrite.writeNext(curCSV.getColumnNames());\r\n        String data;\r\n        while(cursor.moveToNext())\r\n        {\r\n            String mg1 = cursor.getString(cursor.getColumnIndex(\"QTY1\"));\r\n            mg1 = mg1.replace(\".\", \",\");\r\n            data = cursor.getString(cursor.getColumnIndex(\"ARTNR\")) + \";\" + cursor.getString(cursor.getColumnIndex(\"ARTTXT\")) + \";\" + mg1 + \";\" + cursor.getString(cursor.getColumnIndex(\"LOCATION\"));\r\n            data += \"\\r\\n\";\r\n            fw.write(data);\r\n\r\n        }\r\n        fw.close();\r\n        cursor.close();\r\n    }\r\n    catch(Exception sqlEx)\r\n    {\r\n        Log.e(TAG, sqlEx.getMessage(), sqlEx);\r\n    }\r\n}<\/pre>\n<\/blockquote>\n<hr \/>\n<p>Ich erspare mir jetzt mal, das Ding aufw\u00e4ndig zu kommentieren. Das Meiste ist selbst erkl\u00e4rend und manchmal sind auch noch auskommentierte Optionen im verf\u00fcgbar, die weitere Hinweise oder M\u00f6glichkeiten liefern. Ansonsten gilt: einige Codebeispiele wurden dem Internet entnommen, evtl umgebaut und verwendet. Umfangreiche Quellen kann ich hier (nicht mehr) angeben \/ liegen nicht vor,+<\/p>\n<p>Es sei noch der Hinweis erlaubt, eine andere Idee unter Android mit derartigen Daten zu arbeiten, w\u00e4re die ArryList. Rein subjektiv &#8211; Messergebnisse liegen nicht vor &#8211; scheint uns die ArryList sogar flinker zu sein, wenn die TXT Datei komplett gelesen oder geschrieben werden soll. Hierbei w\u00e4re dann aber zu beachten, dass die Daten aber au\u00dferhalb der Anwendung noch gespeichert sein m\u00fcssen &#8211; z.B. via <a href=\"https:\/\/www.art-events.de\/weblog\/android-programmieren-variablen-uebergeben\/\">SharedPreferences<\/a>, was bei SQLite quasi bereits automatisch passiert.<\/p>\n<p>Text und Entwurf. (c) AE SYSTEME Testcenter<br \/>\nHans-J. Walter\u00a0<a href=\"mailto:hjw@terminal-systems.de\">hjw@terminal-systems.de<\/a><\/p>\n<p><em>Hinweis: Alle Angaben ohne Gew\u00e4hr. Diese Beschreibung bezieht sich auf unsere Installation und stellt keine Bewertung der verwendeten Techniken da.\u00a0<\/em><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mit SQLite liefert uns Android bereits einen vorinstallierten SQL Server f\u00fcr den wir nix mehr tun m\u00fcssen. Also nicht wie aus der PC Welt \u00fcblich: SQL installieren, User anlegen, Rechte definieren etc pp. Sondern unter Android: SQLite ist da. L\u00e4uft. Kann verwendet werden. Was auf einem Smartphone oder Tablett PC nat\u00fcrlich auch bedeutet: da greifen [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1991","page","type-page","status-publish","hentry","entry"],"_links":{"self":[{"href":"https:\/\/www.art-events.de\/weblog\/wp-json\/wp\/v2\/pages\/1991","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.art-events.de\/weblog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.art-events.de\/weblog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.art-events.de\/weblog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.art-events.de\/weblog\/wp-json\/wp\/v2\/comments?post=1991"}],"version-history":[{"count":0,"href":"https:\/\/www.art-events.de\/weblog\/wp-json\/wp\/v2\/pages\/1991\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.art-events.de\/weblog\/wp-json\/wp\/v2\/media?parent=1991"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}