SQL Lite

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
BlackJack

@Padidem: Erst einmal hast Du wahrscheinlich Glück das SQLite so grosszügig mit SQL umgeht, denn der Vergleichsoperator in SQL ist eigentlich nicht ``==``.

Wenn Du bei der Abfrage keine Ergebnisse bekommst, dann sind in der Datenbank schlicht keine Tabellen enthalten. Also in *der* Datenbank. Wahrscheinlich liegt die Datenbank nicht im Arbeitsverzeichnis und Du hast mit dem `connect()`-Aufruf eine neue ``laender.db`` erstellt, die natürlich leer ist.
Padidem
User
Beiträge: 63
Registriert: Donnerstag 8. Januar 2015, 14:52

danke für den Tip :) allerdings habe ich die datei laender.db entpackt und dann direkt auf C:\\ gezogen.
BlackJack

Tja und das Arbeitsverzeichnis von Deinem Programm oder der interaktiven Sitzung wird dann sehr wahrscheinlich nicht direkt das Wurzelverzeichnis des Laufwerks C: sein. Das wäre auch irgendwie komisch.
Padidem
User
Beiträge: 63
Registriert: Donnerstag 8. Januar 2015, 14:52

super ... vielen Dank...habe es jetzt endlich hinbekommen und habe folgenden Output:

[(u'table',
u'laender_info',
u'laender_info',
2,
u'CREATE TABLE laender_info (\n [index] INTEGER,\n [land] TEXT,\n [kuerzel] TEXT,\n [hauptstadt] TEXT,\n [beitrittsdatum] INTEGER,\n [regierungschef] TEXT,\n [regierungspartei] TEXT,\n [stimmgewicht] INTEGER,\n [flaeche] INTEGER,\n [einwohner_mio] REAL,\n [einwohner_km2] INTEGER,\n [auslaender] REAL,\n [sprachen] TEXT\n )'),
(u'table',
u'migrationshintergrund_2013',
u'migrationshintergrund_2013',
5,
u'CREATE TABLE migrationshintergrund_2013 (\n [index] INTEGER,\n [land] TEXT,\n [insgesamt] INTEGER,\n [ohne_mh] INTEGER,\n [mit_mh] INTEGER\n )')]


und wie kann ich nun hieraus folgendermaßen Listen erstellen :
Nur die Namen der Tabelle sollen als Liste formatiert werden. Die Namen der Spalten und deren Datentypen sollen als eine Liste von Zweier-Tupeln formatiert sein, die an erster Stelle den Namen der Spalte und an zweiter Stelle den Datentyp beinhalten.
BlackJack

@Padidem: Als erstes würde ich die Abfrage so schreiben das nur die relevanten Daten geliefert wird und nicht immer die kompletten Datensätze. Und dann musst Du wie schon gesagt das SQL parsen mit dem die Tabellen erstellt wurden das ja in der SQLite-Master-Tabelle hinterlegt ist. Da ist die Frage ob die Lösung jetzt genau mit dieser speziellen DB funktionieren muss, oder grundsätzlich mit jeder DB. Da dort wirklich die SQL-Anweisung gespeichert ist mit der die Tabelle erstellt wurde, muss man da streng genommen alles verarbeiten können was SQLite an ``CREATE TABLE…``-Syntax akzeptiert. Das konkrete Beispiel nutzt ja nur einen sehr kleinen Bruchteil davon. Nicht einmal Primärschlüssel sind ausgezeichnet.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Padidem hat geschrieben:und wie kann ich nun hieraus folgendermaßen Listen erstellen :
Nur die Namen der Tabelle sollen als Liste formatiert werden. Die Namen der Spalten und deren Datentypen sollen als eine Liste von Zweier-Tupeln formatiert sein, die an erster Stelle den Namen der Spalte und an zweiter Stelle den Datentyp beinhalten.
Du nimmst den Text des CREATE-Statements, zerlegst ihn in seine Bestandteile und baust dir eine geeignete Struktur mit Tabellen und Spalten für das Ergebnis auf. Diese kannst du dann ausgeben wie auch immer du möchtest.

Vielleicht lässt sich mit sqlparse da noch etwas vereinfachen.
Padidem
User
Beiträge: 63
Registriert: Donnerstag 8. Januar 2015, 14:52

also die Liste mit den Tabellennamen habe ich nun wie folgt als Liste ausgegeben:

tab_name= cursor.execute('''SELECT name FROM sqlite_master WHERE type == "table"''').fetchall()

wie mache ich das nun genau für die Namen der Spalten inkl. Datentyp?? :K

Könnte mir jemand den Code hierfür geben?

Vielen Dank für eure Hilfe !
BlackJack

@Padidem: Ähm, die Antwort wird nicht einfacher, egal wie oft Du fragst: Du musst die jeweilige SQL-CREATE-Anweisung parsen. Das ist nicht leicht.

Ausser es ist eine Lösung gefragt die nur mit den Beispieldaten funktioniert, aber nicht mehr funktioniert wenn man es auf eine andere Datenbank anwendet oder sich die Anweisungen bei der vorhandenen Datenbank ändern. Zum Beispiel weil Primär- und Fremdschlüssel hinzugefügt werden, was man eigentlich bei jeder Datenbank mindestens erwarten würde.

Alternativ kannst Du nach einer fertigen Bibliothek suchen. `sqlparse` wurde schon erwähnt. Das halte ich aber nicht unbedingt für geeignet weil der entsprechende Teil mit den Deklarationen den man sich aus dem geparsten ``CREATE`` herausfischen kann so aussieht:

Code: Alles auswählen

In [82]: p.tokens
Out[82]: 
[<Punctuation '(' at 0x8ea4824>,
 <Newline ' ' at 0x8ea47d4>,
 <Whitespace ' ' at 0x8ea47fc>,
 <Identifier '[index]' at 0x8ea326c>,
 <Whitespace ' ' at 0x8ea489c>,
 <Builtin 'INTEGER' at 0x8ea49b4>,
 <Punctuation ',' at 0x8ea4d24>,
 <Newline ' ' at 0x8ea466c>,
 <Whitespace ' ' at 0x8ea4f7c>,
 <Identifier '[land]' at 0x8ea32ac>,
 <Whitespace ' ' at 0x8ea4cfc>,
 <Builtin 'TEXT' at 0x8ea4374>,
 <Punctuation ',' at 0x8ea4cd4>,
 <Newline ' ' at 0x8ea4d74>,
 <Whitespace ' ' at 0x8ea4234>,
 <Identifier '[kuerz...' at 0x8ea32ec>,
 <Whitespace ' ' at 0x8ea4324>,
 <Builtin 'TEXT' at 0x8ea4874>,
 <Punctuation ',' at 0x8ea443c>,
 <Newline ' ' at 0x8ea439c>,
 <Whitespace ' ' at 0x8ea4eb4>,
 <Identifier '[haupt...' at 0x8ea332c>,
 <Whitespace ' ' at 0x8ea470c>,
 <Builtin 'TEXT' at 0x8ea4dec>,
 <Punctuation ',' at 0x8ea4c0c>,
 <Newline ' ' at 0x8ea457c>,
 <Whitespace ' ' at 0x8ea4f54>,
 <Identifier '[beitr...' at 0x8ea336c>,
 <Whitespace ' ' at 0x8ea4edc>,
 <Builtin 'INTEGER' at 0x8ea4fcc>,
 <Punctuation ',' at 0x8ea4d4c>,
 <Newline ' ' at 0x8ea4b6c>,
 <Whitespace ' ' at 0x8ea4914>,
 <Identifier '[regie...' at 0x8ea33ac>,
 <Whitespace ' ' at 0x8ea4dc4>,
 <Builtin 'TEXT' at 0x8ea4554>,
 <Punctuation ',' at 0x8ea42d4>,
 <Newline ' ' at 0x8ea4694>,
 <Whitespace ' ' at 0x8ea47ac>,
 <Identifier '[regie...' at 0x8ea33ec>,
 <Whitespace ' ' at 0x8ea4504>,
 <Builtin 'TEXT' at 0x8ea48c4>,
 <Punctuation ',' at 0x8ea475c>,
 <Newline ' ' at 0x8ea4b1c>,
 <Whitespace ' ' at 0x8ea461c>,
 <Identifier '[stimm...' at 0x8ea342c>,
 <Whitespace ' ' at 0x8ea4c5c>,
 <Builtin 'INTEGER' at 0x8ea4acc>,
 <Punctuation ',' at 0x8ea46e4>,
 <Newline ' ' at 0x8ea44dc>,
 <Whitespace ' ' at 0x8ea4c84>,
 <Identifier '[flaec...' at 0x8ea346c>,
 <Whitespace ' ' at 0x8ea4f2c>,
 <Builtin 'INTEGER' at 0x8ea43ec>,
 <Punctuation ',' at 0x8ea448c>,
 <Newline ' ' at 0x8ea49dc>,
 <Whitespace ' ' at 0x8ea4aa4>,
 <Identifier '[einwo...' at 0x8ea34ac>,
 <Whitespace ' ' at 0x8ea48ec>,
 <Builtin 'REAL' at 0x8ea4cac>,
 <Punctuation ',' at 0x8ea4a04>,
 <Newline ' ' at 0x8eab0f4>,
 <Whitespace ' ' at 0x8eab1bc>,
 <Identifier '[einwo...' at 0x8ea34ec>,
 <Whitespace ' ' at 0x8eab0a4>,
 <Builtin 'INTEGER' at 0x8eab144>,
 <Punctuation ',' at 0x8eab11c>,
 <Newline ' ' at 0x8eab07c>,
 <Whitespace ' ' at 0x8eab234>,
 <Identifier '[ausla...' at 0x8ea352c>,
 <Whitespace ' ' at 0x8eab20c>,
 <Builtin 'REAL' at 0x8eab2d4>,
 <Punctuation ',' at 0x8eab2fc>,
 <Newline ' ' at 0x8eab054>,
 <Whitespace ' ' at 0x8eab02c>,
 <Identifier '[sprac...' at 0x8ea356c>,
 <Whitespace ' ' at 0x8eab0cc>,
 <Builtin 'TEXT' at 0x8eab194>,
 <Newline ' ' at 0x8eab1e4>,
 <Whitespace ' ' at 0x8eab25c>,
 <Punctuation ')' at 0x8eab324>]
Für die vorhandene Tabelle kann man sich da jetzt natürlich paarweise die `Identifier`- und `Builtin`-Exemplare heraus fischen, aber das würde von der Robustheit einer billigen Lösung mit Zeichenkettenoperationen entsprechen. `sqlparser` gruppiert nicht die einzelnen Spaltendeklarationen und das wird halt kompliziert wenn da noch Primär-, Fremdschlüssel-, oder weitere Constraints angegeben werden. Da würde ich mir dann doch eher eine Parserbibliothek wie `pyparsing` und die SQLite-Dokumentation schnappen und selbst einen Parser schreiben der ein Ergebnis liefert was mehr in die Richtung geht die man hier benötigt.

SQLAlchemy wäre vielleicht noch ein Ansatz und dort dann versuchen ob bei SQLite „reflection” gut genug funktioniert.

Das erscheint mir insgesamt nicht als anfängertaugliche Aufgabe wenn da etwas heraus kommen soll was kein hässlicher Hack ist. Denn alles andere ist dann doch ein klein wenig komplexer.
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

wenn ich eine von Django erstelle SQLite-DB öffnen (wo also garantiert div. Tabellen drin sind) und mit

SELECT * FROM sqlite_master

abfrage, bekomme ich auch eine leere Liste als Ergebnis... Warum auch immer, denn der Befehl ist wohl richtig - wird auch in diversen Thread bei SO empfohlen.

Gruß, noisefloor
BlackJack

@noisefloor: Wenn die Abfrage ein leeres Ergebnis liefert dann sind da keine Tabellen in der Datenbank.

@Padidem: Mit SQLAlchemy lassen sich die gewünschten Informationen ermitteln. Ist nicht besonders schwer, und es ist vor allem robust und zuverlässig. Sogar unabhängig von dem verwendeten DBMS mal von der URL für die Datenbankverbindung abgesehen und man muss auch nicht selber ein SELECT absetzen. Das geht alles über das `Metadata`-Objekt.
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
BlackJack hat geschrieben:@noisefloor: Wenn die Abfrage ein leeres Ergebnis liefert dann sind da keine Tabellen in der Datenbank.
Na ja... wo du recht hast, hast du recht :-) Habe eben einen Fehler gemacht (habe die db.sqlite statt db.sqlite3 genommen - erster ist wirklich leer...)

Funktioniert in der Tat so, wie es soll:

Code: Alles auswählen

>>> import sqlite3
>>> conn = sqlite3.connect('db.sqlite3')
>>> c = conn.cursor()
>>> c.execute("SELECT * FROM sqlite_master WHERE type='table'")
<sqlite3.Cursor object at 0x7f7a85130730>
>>> c.fetchall()
[('table', 'django_migrations', 'django_migrations', 2, 'CREATE TABLE "django_migrations" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "app" varchar(255) NOT NULL, "name" varchar(255) NOT NULL, "applied" datetime NOT NULL)'), ('table', 'sqlite_sequence', 'sqlite_sequence', 3, 'CREATE TABLE sqlite_sequence(name,seq)'), ('table', 'django_content_type', 'django_content_type', 5, .... 
Gruß, noisefloor
Padidem
User
Beiträge: 63
Registriert: Donnerstag 8. Januar 2015, 14:52

Gibt es eine Methode, wie ich Daten aus einer .txt Datei die folgendermaßen aussieht:

Code: Alles auswählen

Bundesland	2005	2006	2007	2008	2009	2010	2011	2012	2013
Deutschland	14.7	14.0	14.3	14.4	14.6	14.5	15.0	15.0	15.5
Altes Bundesgebiet ohne Berlin	13.2	12.7	12.9	13.1	13.3	13.3	13.8	13.9	14.4
Neue Bundeslaender mit Berlin	20.4	19.2	19.5	19.5	19.5	19.0	19.4	19.6	19.8
Baden-Wuerttemberg	10.6	10.1	10.0	10.2	10.9	11.0	11.1	11.1	11.4
Bayern	11.4	10.9	11.0	10.8	11.1	10.8	11.1	11.0	11.3
Berlin	19.7	17.0	17.5	18.7	19.0	19.2	20.6	20.8	21.4
Brandenburg	19.2	18.9	17.5	16.8	16.7	16.3	16.8	18.1	17.7
Bremen	22.3	20.4	19.1	22.2	20.1	21.1	22.0	22.9	24.6
Hamburg	15.7	14.3	14.1	13.1	14.0	13.3	14.7	14.8	16.9
Hessen	12.7	12.0	12.0	12.7	12.4	12.1	12.8	13.3	13.7
Mecklenburg-Vorpommern	24.1	22.9	24.3	24.0	23.1	22.4	22.1	22.8	23.6
Niedersachsen	15.5	15.3	15.5	15.8	15.3	15.3	15.5	15.7	16.1
Nordrhein-Westfalen	14.4	13.9	14.6	14.7	15.2	15.4	16.4	16.3	17.1
Rheinland-Pfalz	14.2	13.2	13.5	14.5	14.2	14.8	15.1	14.6	15.4
Saarland	15.5	16.0	16.8	15.8	16.0	14.3	15.2	15.4	17.1
Sachsen	19.2	18.5	19.6	19.0	19.5	19.4	19.5	18.8	18.8
Sachsen-Anhalt	22.4	21.6	21.5	22.1	21.8	19.8	20.6	21.1	20.9
Schleswig-Holstein	13.3	12.0	12.5	13.1	14.0	13.8	13.6	13.8	14.0
Thueringen	19.9	19.0	18.9	18.5	18.1	17.6	16.7	16.8	18.0
in eine neu erstellte Tabelle einfügen kann ?
Zuletzt geändert von Anonymous am Samstag 10. Januar 2015, 13:19, insgesamt 1-mal geändert.
Grund: Daten in Code-Tags gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ja:

Code: Alles auswählen

from exercises.common import solver
solver.do_magic_with(guess_data_from_somewhere())
:twisted:

SCNR

Mal kurz ein wenig Meta-Diskussion:
Du hattest zuvor eine gänzlich andere Frage (wenn auch zum Thema Arbeiten mit einer DB) gestellt und springst nun kommentarlos - *ohne* auf die Rückfragen und Anmerkungen der bisherigen Helfenden einzugehen! - zu einer komplett anderen Frage. So etwas ist imho stillos. Immerhin haben sich Leute bemüht, Dir bei Deinem ursprünglichen Problem zu helfen. Da hättest Du zumindest kurz etwas dazu erwähnen können.
Zudem ist es hier eigentlich üblich, zu einer neuen Frage auch ein neues Thema zu eröffnen. Zum einen gruppiert das halt einfach Themen sinnvoll, zum anderen lassen sich so Fragen und deren Antworten einfacher über die Suchfunktion finden. Also in Zukunft bitte daran denken :-)

Jetzt eine ernsthafte Antwort zur neuen Frage: Du musst das einfach programmieren. Punkt. ;-)
Du musst dazu wohl Daten aus einer Datei lesen und zudem Daten per SQL in eine Tabelle einfügen können. Für beides gibt es Funktionen. Da die Datei ein CSV-Format besitzt, böte sich für das Einlesen das ``csv``-Modul aus der Standardlib von Python an. Damit kannst Du über alle Zeilen der Datei einfach iterieren und erhältst eine Sammlung von Spalten. Diese kannst Du dann über ein ``INSERT``-Statement in eine geeignete Tabelle der Datenbank überführen.
Das Vorgehen an sich ist also wenig anspruchsvoll...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

und wer auch immer die Tabelle erstellt hat sollte sich mal gedanken über korrekte Spaltenbezeichner machen - Deutschland ist z.B. kein Bundesland *SCNR*

Gruß, noisefloor
Padidem
User
Beiträge: 63
Registriert: Donnerstag 8. Januar 2015, 14:52

danke für den Hinweis...ich bin ja noch neu hier bei meine nächsten Frage werde ich dann natürlich ein neues Thema eröffnen :)

meintest du das mit dem einlesen so:

with open('armutsgefahr.txt', 'rb') as csvfile:
spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
for row in spamreader:
print ', '.join(row)
BlackJack

@Hyperion: So einfach würde ich das einlesen nicht sehen, denn die Datenbanktabelle wird ja wohl hoffentlich nicht 1:1 so aussehen wie die Daten in der Datei angeordnet sind. Die Jahreszahlen sind ja keine sinnvollen Spalten. Auch wenn man es transponiert sind die ”Bundesländer” nicht wirklich sinnvoll für Spalten geeignet, sondern wären genau wie die Jahreszahlen eher Daten. Die ersten drei Zeilen nach der Kopfzeile sind redundant, die würden bei einem sinnvollen DB-Entwurf rausfliegen.

Also es ist keine Raketenwissenschaft, aber ein klein bisschen "Transformation" und verteilen auf mindestens zwei Tabellen ist im Code dann schon erforderlich.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@BlackJack: Ich habe mir die Daten nicht wirklich genau angesehen. Der OP fragte nach dem Einfügen in *eine* Tabelle - ob das Datenmodell sinnvoll gestaltet ist, habe ich nicht hinterfragt 8)

@Padidem: Bitte benutze doch die speziellen Markups für das Einfügen von Code! Ohne diese kann man Deinen Python-Code kaum sinnvoll lesen, da die Einrückungen verloren gehen. Und ja, so in etwa meinte ich das ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

Die IMHO einzige Lösung zu der Aufgabe mit dem Auflisten von Spaltennamen und -typen die kein hässlicher Hack ist und die man einem Anfänger eventuell, ansatzweise zumuten könnte, auch wenn SQLAlchemy für absolute Programmieranfänger auch erst mal eine ziemliche Hürde sein dürfte weil die Bibliothek ja recht umfangreich ist:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
from sqlalchemy import create_engine, MetaData


def main():
    metadata = MetaData(create_engine('sqlite:///laender.db'))
    metadata.reflect()
    for table in metadata.tables.itervalues():
        print(table.name)
        for column in table.columns:
            print('    {0.name} {0.type}'.format(column))


if __name__ == '__main__':
    main()
Ausgabe:

Code: Alles auswählen

migrationshintergrund_2013
    index INTEGER
    land TEXT
    insgesamt INTEGER
    ohne_mh INTEGER
    mit_mh INTEGER
laender_info
    index INTEGER
    land TEXT
    kuerzel TEXT
    hauptstadt TEXT
    beitrittsdatum INTEGER
    regierungschef TEXT
    regierungspartei TEXT
    stimmgewicht INTEGER
    flaeche INTEGER
    einwohner_mio REAL
    einwohner_km2 INTEGER
    auslaender REAL
    sprachen TEXT
Antworten