Daten in einer mysql Tabelle sortieren

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

Hallo zusammen,
ich möchte Daten von meinem Script aus direkt auf dem mysql Server sortieren.
Technisch bekomme ich es leider nicht so einfach hin wie erhofft.
Bin über jeden Rat dankbar.

Code: Alles auswählen

# Connector importieren
import sys
import mysql.connector

# csv Modul importieren
import csv

# Verbindung zur Datenbank auf dem Datenbankserver erstellen
try:
    connection = mysql.connector.connect (host = "localhost", user = "root", passwd = "", db = "firma")
except:
    print ("Keine Verbindung zum Server")
    sys.exit(0)

# Execution-Objekt erzeugen
cursor = connection.cursor()

# Daten sortieren nach PLZ absteigend
cursor.execute ("SELECT * FROM personen3 ORDER BY zipcode DESC")


connection.commit()

# Execution-Objekt schliessen
cursor.close()

# Verbindung schliessen
connection.close()
Zuletzt geändert von Anonymous am Mittwoch 8. März 2017, 14:41, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@tz_wuerzburg: Du müsstest das Ergebnis von dem sortierten SELECT auch abfragen. Oder willst Du tatsächlich die Daten *in* der Datenbank sortieren? Das solltest Du nicht wollen weil Dich als Programmierer das nichts angeht wie die Datenbank die Daten intern ablegt. Das ist ja unter anderem der Sinn eines DBMS, das man sich nicht um die konkrete Datenhaltung kümmern muss und auch nicht wie der Ablauf hinter den Kulissen ist, wenn man Daten abfragt, weil man mit SQL nicht sagt *wie* die Daten zusammengesammelt werden, sondern nur *welche*.

Einfluss auf die Datenhaltung im DBMS sollte man erst nehmen wenn es messbar zu langsam wird und dann ist das auch keine Python-Frage mehr, denn was immer man da macht, hat keinen Einfluss auf den Code für die Abfrage.
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

@BlackJack
Ok schade, da fehlt mir dann doch noch wirklich einiges an Erfahrung und vor allem Wissen.
Grob umrissen möchte ich eine Software schreiben welche es schafft Postprodukte zu Bundieren
und zu Palettieren, nach diversen Vorgaben (Basis sind Adressen).
Wie muss ich mir dass dann technisch grob vorstellen (um eine Richtung zu haben). Arbeite ich dann mit
Python "internen" Listen oder funktioniert dies über temporäre Tabellen?
Ist mysql dann überhaupt nötig... Fragen über Fragen.
Irgendwo muss das Abgefragte und sortierte ja "gespeichert" werden.
Vielen Dank für die Unterstützung!
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Warum muss es gespeichert werden? Zumindest im strengeren Sinne bedeutet versteht man darunter ja eine dauerhafte Ablage. Dazu gibt es an sich keinen Grund. Zur *Laufzeit* innerhalb eines Programms hat man solche oder andere Daten natuerlich in Datenstrukturen wie Listen oder Woerterbuechern zur Verfuegung.

Eine Datenbank fuer die Vorhaltung von Stammdaten und Protokollierung von durchgefuehrten Aktionen ist wahrscheinlich trotzdem sinnvoll, Adressen (also Kundenkontakte) muessen ja irgendwo dauerhaft hinterlegt werden, genauso wie die zu buendelnden Produkte.
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

Hallo zusammen,
ich bin dank Eurer Hilfe wieder einen Schritt weiter gekommen.
Das import csv Modul ist die für mich die beste Lösung um die Daten einzulesen.
Jetzt geht es aber weiter:
Ich möchte meine Daten einem PLZ Gebiet zuordnen. Zum Beispiel (Gebiet 1 = 100-249, Gebiet 2 = 250-270, usw) um dann später
daraus eine Palette bilden zu können. Es sollen alle Sendungen aus diesem PLZ Gebiet auf diese Palette, so die finale Idee.

Grundsätzlich benötige ich nicht den Code um dorthin zu kommen, sondern, wenn möglich, eine
Info wie ich das Ganze am besten angehe.
Selektiere ich die Daten aus meiner Liste und schreibe eine komplett neue csv. mit allen Daten aus einem Gebiet oder
schreibe ich eine neue csv. mit allen Datensätzen, reichere diese aber in einer neuen Spalte mit den Gebietsinformationen an?

Vielen Dank vorab für Eure Hilfe.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@tz_wuerzburg: Du schreibst die Daten so, wie Du sie brauchst, um damit weiterarbeiten zu können. Warum überhaupt ein Export in eine CSV-Datei? Welche Gedanken hast Du Dir für die Zuordnung Gebiet -> PLZ gemacht?
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

Grundsätzlich ist es schwierig für mich an die Logik zu kommen, da ich die Daten vorher mit Excel
und diversen benutzerfreundliche Datenbanksystemen manipuliert habe.
Hier gibt es eine große Datei aus der ich meine Informationen nehme, diese zwischenspeichere
und sie mir, wenn benötigt, wieder ziehe.

Mir fehlt das logische Verständnis für die Manipulation von Daten, bzw. Listen in Python. Gegeben sind als Bespiel
10.000 Datensätze, welche wie beschrieben ersteinmal auf die Gebiete aufgeteilt werden sollen. Um es für mich greifbarer
zu machen, würde ich das ganze immer in einem neuen File zwischenspeichern, auch der Kontrolle wegen.

Der Schritt des aufteilens soll ein weiterer Schritt der Verarbeitung darstellen.
Folgende Punkte sind hier noch nicht berücksichtig, werden aber im weiteren Verlauf relevant:
- Das Palettengewicht ist variabel (z.B. 50kg bis 500kg)
- Das Produktgewicht muss beachtet werden (pro Datensatz identisch)
- Falls das Mindestgewicht einer Palette nicht erreicht wird soll es einen Rest geben

Im Idealfall gibt es am Ende des Prozesses meine eingelesene Datei mit den entsprechenden Informationen
(Palettennummern) wieder aus.

Mein Problem ist, dass ich nicht weiß in welche Richtung ich gehen soll. Daten in einer Datenbank zwischenspeichern?
Daten in csv. Dateien ablegen? Listen verwenden?
BlackJack

@tz_wuerzburg: So wirklich wissen wir auch nicht in welche Richtung Du gehen solltest, weil das davon abhängt wie die Zugriffsmuster auf die Daten aussehen und wie ja schon angesprochen wurde, ob und was persistent gepeichert werden muss und was nur Zwischenergebnisse sind die man nicht dauerhaft speichern muss.

Wenn Du die Daten auf Gebiete aufteilen möchtest, hängt das vorgehen wahrscheinlich davon ab ob sie schon nach Postleitzahlen sortiert sind, dann könnte man sie wahrscheinlich linear mit `itertools.groupby()` verarbeiten, oder nicht, dann würde sich wahrscheinlich `collections.defaultdict()` zum aufteilen anbieten. Was auch nicht uninteressant wäre ist die Information ob die gesamten Daten aufgeteilt werden, also die Gebiete lückenlos alle PLZs beschreiben die in den Daten vorkommen können, oder ob man auch eine Gruppe hat die nicht erfasst wird.

Grundsätzliches Vorgehen beim Programmieren: Das Problem auf kleinere Teilprobleme aufteilen. Und die Teilprobleme wieder auf Teilprobleme herunterbrechen, solange bis man die Teilprobleme in kurzen Funktionen mit ein paar Zeilen Code lösen kann. Die Teillösungen testen und erst weitermachen wenn sie funktioniert. Irgendwann kann man die kleineren Teillösungen dann zu grösseren Teillösungen zusammensetzen, bis am Ende das Gesamtproblem gelöst ist.

Eine Funktion sollte immer nur eine Aufgabe lösen. Eine grobe Aufteilung funktioniert in der Regel ganz gut zwischen Eingabe, Verarbeitung, und Ausgabe. Also laden und speichern sind jeweils Funktionen. Damit ist dann auch das jeweilige Format nicht mehr ganz so wichtig, weil man es durch austausch von Funktionen ändern kann.

Zusammengehörende Daten sollte man in Datenstrukturen zusammenfassen. `collections.namedtuple()` sind für unveränderbare Daten(sätze) praktisch. Bei veränderbaren Daten sind wir bei Klassen.

Was beispielsweise zusammengehört sind erste und letzte Postleitzahl die zusammen ein Gebiet beschreiben. Als von `namedtuple` abgeleiteter Datentyp kann man so ein Gebiet auch als Schlüssel für ein Wörterbuch verwenden.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@BlackJack: mein Gedanke war jetzt, eine SQL-Tabelle zu haben, in der die Zuordnung Gebiet -> PLZ steht und diesen Schritt schon mysql machen zu lassen. Das Zusammenstellen von Paletten mit einem Maximalgewicht ist ja schon wieder eine neue Aufgabe...
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

Tausend Wege führen nach Rom :)

Ich werde mich mit beiden Ansätzen beschäftigen, sowohl die Möglichkeiten mit
itertools.groupby()
collections.defaultdict()
als auch mit mysql.
Ein Bericht folgt dann die nächsten Tage.

Vielen Dank für Eure Hilfe!
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

Hallo zusammen,
ich habe nun ein wenig Zeit und Lust intensiver in die Programmierung einzustiegen.
Aktuell mache ich einen online Kurs, komme gut voran, möchte nebenbei aber auch mein Projekt
voran treiben.

Daten einlesen und abfragen habe ich soweit verstanden. Das Problem ist, immer wenn ich mit Listen
arbeite habe ich Excel im Kopf. Das ist aber wohl grundlegend falsch :)

Code: Alles auswählen

pal_liste = []
palname = []
with open ("paletten_gebiete.csv") as paletten_gebiete, open ("adresse.csv") as file:
    
    for pal in paletten_gebiete:
        pal = pal.strip().split(";")
        pal_plz = pal[1]     # PLZ aus paletten_gebiete.csv
        palname = pal[2]    # Palettenname aus paletten_gebiete.csv
        
    
    	for data in file: 
        	data = data.strip().split(";")
        	database = data[3]      # PLZ aus adresse.csv
        	if pal_plz in database:
            		data.append(palname)
        	elif pal_plz in database:
           		data.append(palname)
        	else: 
            		data.append(palname)
        
		print (database)	
Was erreicht werden soll.
Es liegt eine Adresse in Listenform vor. Hier möchte ich in jeder Zeile nachsehen, welche PLZ vorhanden ist. Ist z.B.
die PLZ 01234 vorhanden, gebe mir PLZ_GEBIET_1 aus.
Am Ende soll die Liste dann so aussehen:
['Musterort' , '01234' , 'PLZ_GEBIET_1']
['Musterort' , 01235' , 'PLZ_GEBIET_1']
['Musterort' , 01236' , 'PLZ_GEBIET_2']
['Musterort' , 01236' , 'PLZ_GEBIET_2']

Wie gesagt, ich lerne fleißig, aber das Verständnis "Tabelle" zu "Liste" will noch nicht so richtig :)
Ich danke Euch!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@tz_wuerzburg: Deine Einrückungen sind kaputt. So ist das Programm gar nicht lauffähig. Wenn das eine verschachteltes Lesen von Dateien sein soll, dann funktioniert das so gar nicht, denn wenn eine Datei einmal ausgelesen ist, dann liefert die innere for-Schleife kein Ergebnis mehr.

Ein if und ein elif mit der selben Bedingung ist sinnlos, wenn dazu ein else-Block mit dem selben Inhalt kommt, dann ist das ganze if-Konstrukt sinnlos. `in` ist auch der falsche Parameter, weil doch wahrscheinlich die Postleitzahlen immer gleich viele Stellen haben und komplett verglichen werden sollen.

Das Lesen der Gebiete und das Anwenden dieser Information sind zwei Schritte, die am Besten auch in zwei Funktionen passieren.
Da Du eine Zuordnung PLZ -> Gebiet haben willst, böte sich als Datenstruktur ein Wörterbuch an.
Schreibe am besten erst eine Funktion, die genau diese Wörterbuch generiert. Wie man die Addressen dann um diese Information anreichert, wäre dann erst der zweite Schritt.
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

@Sirius3
if Bedingungen sind nicht mehr vorhanden, sorry. Hab soviel damit rumgebastel und dann vorhin
übersehen diese wieder zu ergänzen.

Wörterbuch = dictionary { } ?
Die Vorgehensweise wäre dann:
Key = die PLZ (01234) Wert = das Gebiet (Palette1)
Habe ich das richtig verstanden?

Kann ich eine .csv auch in ein dictionary "einlesen"?
Der nächste Punkt wäre dann wie ich diese Daten dann für das gesamte Script
im Speicher hinterlegen kann.
Nach meinem Verständnis macht eine for Schleife dann ja keinen Sinn.

Danke schonmal!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@tz_wuerzburg: ja, Wörterbuch ist {}. Und wie die csv in ein Wörterbuch eingelesen wird, mußt Du programmieren. Die anderen Fragen versteh ich nicht. Daten werden in Variablen gespeichert und den Funktionen, die sie brauchen als Parameter übergeben. Und Schleifen machen dort Sinn, wo man Schleifen braucht.
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

Ein bisschen weiter bin ich schon gekommen.
In nächster Instanz werde ich versuchen es mit noch mehr Variablen zu versehen.
Habt ihr Tipps um den Code noch zu verbessern?

Code: Alles auswählen

database = []

with open ("adressen.csv","r") as file:
    
    for data in file:
        data = data.strip().split(";")
        database = data[1]
        database = int(database[:3])
        
        if int(database) >= 100 and database <= 249:
            database = "text 1"
        elif int(database) >= 250 and database <= 299:
            database = "text 2"
        else: 
            database = "text 3"
 
        print (str(data[1]) + str(" : " ) + str(database))
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn du dir Muehe gibst, kannst du bestimmt noch irgendwo ein int(database) mehr unterbringen :wink:

Das erste ist notwendig. Die beiden danach nicht, und es ist ungewoehnlich, einen Namen dann an einen anderen Wert zu binden, der auch noch einen anderen Datentyp hat. Statt also immer database zu recyceln, nenn die Variable anders (wie kann ich an dem Snippet nun auch nicht erkennen)

Und danach nochmal str(database) ist natuerlich ebenfalls voellig ueberfluessig, wenn da schon ein string drin ist.
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

@deets.
Vielen Dank für deine Hinweise. Der Code ist jetzt überarbeitet und sollte so jetzt passen.
Schreibe das Ergebnis jetzt noch in eine andere .csv, für das Erfolgserlebnis :)

Code: Alles auswählen

database = []
ready = []

with open ("adressen.csv","r") as file, open ("adressen_ausgabe.csv","w") as ausgabe:
    
    for data in file:
        data = data.strip().split(";")
        plz_data = data[1]
        plz_3digits = int(plz_data[:3])
        
        if plz_3digits >= 100 and plz_3digits <= 249:
            plz_3digits = "Text 1"
        elif plz_3digits >= 250 and plz_3digits <= 299:
            plz_3digits = "Text 2"
        else: 
            plz_3digits = "Text 3"
 
        ready = (data[0] + "; " + data[1] + "; " + data[2] + "; " + plz_3digits + "\n")
    
        print (ready)
        
        ausgabe.write(ready)
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@tz_wuerzburg: Du benutzt immer noch die selbe Variable für PLZ und PLZ-Gebiet, nur dass es nun plz_3digits statt database heißt.
Wenn Du Dich die ersten beiden Ziffern nicht interessieren, dann nimmt man die 5-stellige PLZ und teilt sie durch 100. Hier würde ich aber einfach auf die 5 Stellen prüfen. Benutze ';'.join oder gleich besser das csv-Modul. database und ready werden initalisiert aber nicht benutzt.

Code: Alles auswählen

with open("adressen.csv") as input_lines, open("adressen_ausgabe.csv", "w") as output:
    for entry in input_lines:
        entry = entry.strip().split(";")
        postal_code = int(entry[1])
        if postal_code >= 10000 and postal_code <= 24999:
            area_code = "Text 1"
        elif postal_code >= 25000 and postal_code <= 29999:
            area_code = "Text 2"
        else: 
            area_code = "Text 3"
        entry.append(area_code)
        output.write(';'.join(entry) + '\n')
Die Herausforderung, die Daten aus einer zweiten Datei herhauszuholen, hast Du aufgegeben??
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

@Sirius3.
Vielen Dank, der Code funktioniert einwandfrei.
Jetzt möchte ich einen Schritt weiter gehen und die PLZ Werte, die abgeglichen werden sollen auch
aus einer .csv ziehen und als Variable weiter verarbeiten.
Ich weiß leider nur nicht wie, bzw. habe ich die Logik dahinter noch nicht verstanden.

In erster Instanz öffne ich die "paletten_gebiete.csv", lege mir diese für meinen Code zurecht,
beende die Schleife dann aber wieder ohne damit in der zweiten Schleife etwas anfangen zu können.

Hier liegt mein Problem. Wie kann ich die Variablen "pal_zip_begin", "pal_zip_end" und den "area_code"
behalten und in dem Script weiter verwerten?

Code: Alles auswählen


with open ("paletten_gebiete.csv", "r") as input_lines_pallet:
    
    for entry_pal in input_lines_pallet:
        entry_pal = entry_pal.strip().split(";")
        pal_zip_begin = int(entry_pal[1])
        pal_zip_end = int(entry_pal[2])
        area_code = (entry_pal[3])
        
        
with open ("adressen.csv","r") as input_lines_adress, open ("adressen_ausgabe.csv","w") as output:
    
    for entry_adress in input_lines_adress:
        entry_adress = entry_adress.strip().split(";")
        postal_code = int(entry_adress[1])
        
        if postal_code >= pal_zip_begin and postal_code <= pal_zip_end:
            area_code_output = area_code
        elif postal_code >= pal_zip_begin and postal_code <= pal_zip_end:
            area_code_output = area_code
        else: 
            area_code_output = area_code
 
        entry_adress.append(area_code_output)
        output.write(";".join(entry_adress) + "\n")
    
        print (entry_adress)
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst sie in eine Datenstruktur stecken. Welche dazu geeignet ist kann ich nicht sagen, das haengt davon ab, was du damit machen willst.
Antworten