Befüllen eine SQLLite DB aus CSV, aufgrund Auswahlkriterium einer anderen CSV

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
DirtyLittleHelper
User
Beiträge: 6
Registriert: Samstag 8. Mai 2021, 20:49

Einen wunderschönen sonnigen guten Abend,
ich bin wie sich sicher gleich unschwer erkennenlässt, ein "Neuling" in Sachen Programmieren und Python.
Leider komme ich trotz Suchfunktion und GidF.de einfach nicht weiter.

Um Python zu lernen habe ich mir ein sehr konkretes Projekt überlegt, welches mit der Zeit immer komplexer werden kann (jenachdem wie meine Skills wachsen).
Leider scheitere ich schon bei den Grundlagen.

Ich habe 2 CSV Datein, Datei 1 = Types.csv (in dieser ist eine Reihe von Gegenständen inklusive Beschreibungen Attributen und vor allem mit einer TypeID und GruppenID) , in der anderen CSV, Datei 2 =Groups.csv stehen die GruppenIDs die für mein Projekt relevant sind.

Ich möchte nun die Daten aus Types in eine SQLite3 DB überführen, aber eben nur dann wenn der Gegenstand in einer der Gruppen ist die für mich relevant sind.
Das Filtern nach einem fixen Wert wie z.B. == "18" ist kein Problem, allerdings bekomme ich das mit Groups nicht hin.

Hinweis: in Types ist O=TypeID 1=GroupID 2=Name 5=Wert

Vorab schonmal vielen Dank für eure Unterstützung. Aber Bitte bitte, keine komplette Lösung! Gebt mir nen Schubs von mir aus auch Tritt! Aber ich will lernen warum es nicht geht.

Code: Alles auswählen

import sqlite3
import csv

# ERSTELLEN DATENBANK und TABELLEN
connection = sqlite3.connect("DLH.DB")
cursor = connection.cursor()

cursor.execute(
    "CREATE TABLE IF NOT EXISTS types (typeID INTEGER, groupID INTEGER, typeName TEXT, volume REAL)")
connection.commit()

# FILTERN CSV DATEI nach GRUPPEN
#erstellen der Liste "Gruppen" aus der CSV Groups
with open("groups.csv", encoding="UTF8") as csvfile:
    csv_reader_object = csv.reader(csvfile)
    groups = list(csv_reader_object)
    groups.pop(0)			# Kopfzeile Entfernen

#Abgleich der Types.csv mit der Liste "Gruppen"
with open("types.csv", encoding="UTF8") as csvfile2:
    csv_reader_object2 = csv.reader(csvfile2)
    for line in csv_reader_object2:
        if (line[1]) in str(groups):
  #    if (line[1]) == "18":			Das würde funktionieren
             connection = sqlite3.connect("DLH.DB")
            cursor = connection.cursor()
            cursor.execute(
                "INSERT INTO types VALUES(?,?,?,?)", (line[0],line[1],line[2],line[5]))
            connection.commit()
connection.close()
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Statt die Kopfzeile nachträglich zu entfernen, packt man sie erst gar nicht in die Liste:

Code: Alles auswählen

with open("groups.csv", encoding="UTF8") as csvfile:
    csv_reader = csv.reader(csvfile)
    _ = next(csv_reader) # Kopfzeile Entfernen
    groups = list(csv_reader)
Warum wandelst Du die Liste groups in ihre Stringrepräsentation um? Um zu prüfen, ob eine Element in einer Liste ist benutzt man nur den in-Operator.
DirtyLittleHelper
User
Beiträge: 6
Registriert: Samstag 8. Mai 2021, 20:49

Sirius3 hat geschrieben: Sonntag 9. Mai 2021, 18:43 Statt die Kopfzeile nachträglich zu entfernen, packt man sie erst gar nicht in die Liste:

Code: Alles auswählen

with open("groups.csv", encoding="UTF8") as csvfile:
    csv_reader = csv.reader(csvfile)
    _ = next(csv_reader) # Kopfzeile Entfernen
    groups = list(csv_reader)
Warum wandelst Du die Liste groups in ihre Stringrepräsentation um? Um zu prüfen, ob eine Element in einer Liste ist benutzt man nur den in-Operator.
Hallo und schonmal Danke fürs Zeitnehmen.

Nun ich bin Neuling, und mittels pop war für mich ein gangbarer weg. Der Andere war mir nicht bekannt.
Das mit dem IN Operator ist mir klar. Allerdings kam ohne das umwandeln in einen String eine Leere DB bei heraus.
Beim Umwandeln in einen String, kam eine befüllte DB heraus, leider aber nicht richtig gefiltert.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Dann wäre der nächste Schritt, ausgeben zu lassen, was denn in der Liste groups und in line drinsteht.

Eigentlich ist ja eine Datenbank zum Filtern da, so dass man das nicht selbst programmieren braucht.
DirtyLittleHelper
User
Beiträge: 6
Registriert: Samstag 8. Mai 2021, 20:49

Code: Alles auswählen

print(groups)
Ausgabe:
[['12'], ['340'], ['448'], ['649'], ['18'], ......]

wenn ich mit

Code: Alles auswählen

    for line in csv_reader_object:
        if (line[1]) in str(groups):
        print(line[0],line[1],line[2],line[5])
Ausgabe:
0 0 Alpha 0E-10
2 2 Bravo 0E-10
3 3 Charly 0E-10
4 4 Delta 0E-10
(Keine der Aufgrführen Gruppen Nummern ist in Groups vorhanden)

wenn ich mit

Code: Alles auswählen

    for line in csv_reader_object:
        if (line[1]) in groups:
        print(line[0],line[1],line[2],line[5])
Ausgabe: Process finished with exit code 0
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Und was fällt Dir an [['12'], ['340'], ['448'], ['649'], ['18'], ......] auf?
DirtyLittleHelper
User
Beiträge: 6
Registriert: Samstag 8. Mai 2021, 20:49

Sirius3 hat geschrieben: Sonntag 9. Mai 2021, 20:02 Und was fällt Dir an [['12'], ['340'], ['448'], ['649'], ['18'], ......] auf?
Nun das Ausgabeformat ist seltsam, die zweite [] .. ich habe danach gesucht ob dictionary, Liste oder tuple..
Darum bin ich ja hier weil ich nicht weiter weiß. Das es etwas mit der Formatierung und dem Zugriff darauf zu tun hat, weiß ich.
Nur habe ich schlicht keinen Plan.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Eckigen Klammern zeigen an, dass es sich um eine Liste handelt, konkret um Listen die in einer Liste stecken. Die inneren Listen mußt Du loswerden, um mit dem in-Operator richtig arbeiten zu können.
DirtyLittleHelper
User
Beiträge: 6
Registriert: Samstag 8. Mai 2021, 20:49

Sirius3 hat geschrieben: Sonntag 9. Mai 2021, 20:49 Die Eckigen Klammern zeigen an, dass es sich um eine Liste handelt, konkret um Listen die in einer Liste stecken. Die inneren Listen mußt Du loswerden, um mit dem in-Operator richtig arbeiten zu können.
dann schonmal vielen Dank.. dann werde ich mal schauen wie ich das knacke.. bisher hab ich da nicht wirklich nen plan.. aber nun ist erstmal wieder Gidf.de dran :-)
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Da muß man nichts googeln, sondern die Pythondokumentation lesen und ein Tutorial zu Listen durcharbeiten.
DirtyLittleHelper
User
Beiträge: 6
Registriert: Samstag 8. Mai 2021, 20:49

Sirius3 hat geschrieben: Sonntag 9. Mai 2021, 21:18 Da muß man nichts googeln, sondern die Pythondokumentation lesen und ein Tutorial zu Listen durcharbeiten.
Ja, mit Append wird dir geholfen. Problem gelöst.
Wie gesagt, danke für den Tritt.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@DirtyLittleHelper: Anmerkungen zum Quelltext:

Die Verbindung zur Datenbank sollte man nur einmal erstellen und im ganzen Programm benutzen. Ausserdem sollte man die Verbindung am Ende auch ordentlich schliessen. Dein Code aus dem ersten Beitrag schliesst nur die allerletzte von den vielen erstellten Verbindungen am Ende.

Warum schreist Du in einigen Kommentaren?

Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Cursor-Objekte sollte man auch wieder schliessen. Bei so einem kleinen Programm würde ich auch nur einen Cursor erstellen, maximal zwei. Einmal zum erstellen der Tabelle und dann zum befüllen.

Bei CSV-Dateien muss man beim öffnen das `newline`-Argument passend angeben. Siehe Dokumentation vom `csv`-Modul.

Der Namenszusatz `_object` ist in der Regel sinnlos weil der nichts aussagt. In Python ist *alles* ein Objekt was man an einen Namen binden kann.

Für den Test auf „enthalten sein“ sind Mengen effizienter als Listen.

Man nummeriert keine Namen. Es ist auch überhaupt gar nicht notwendig an Namen eine 2 anzuhängen wenn die Namen ohne den Zusatz gar nicht mehr benutzt werden.

`line` bezeichnet eher eine Zeile in einer Textdatei. Für Zeilen in Tabellen ist `row` üblicher.

Ich würde nicht jeden Datensatz einzeln committen. Man könnte hier ausserdem `executemany()` verwenden.

Man sollte die Daten auch in die entsprechenden Typen umwandeln. SQLite3 ist da sehr lax was Typen angeht und lässt einen auch eine Zeichenkette in eine INTEGER-Spalte schreiben, aber das wird spätestens beim sortieren oder Rechnen mit solchen Werten zu einem Problem.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import csv
import sqlite3
from contextlib import closing


def main():
    with open("groups.csv", encoding="UTF8", newline="") as file:
        reader = csv.reader(file)
        next(reader)  # Kopfzeile überlesen.
        groups = {row[0] for row in reader}

    with open("types.csv", encoding="UTF8", newline="") as file:
        with closing(sqlite3.connect("DLH.DB")) as connection:
            with closing(connection.cursor()) as cursor:
                cursor.execute(
                    "CREATE TABLE IF NOT EXISTS type ("
                    " id INTEGER PRIMARY KEY,"
                    " group_id INTEGER,"
                    " name TEXT,"
                    " volume REAL)"
                )
                cursor.executemany(
                    "INSERT INTO type (id, group_id, name, volume) VALUES (?,?,?,?)",
                    (
                        (int(row[0]), int(row[1]), row[2], float(row[5]))
                        for row in csv.reader(file)
                        if row[1] in groups
                    ),
                )
                connection.commit()


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten