Mysql Cursor Datensatz über ID lokalisieren

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Bucket
User
Beiträge: 2
Registriert: Montag 5. Februar 2018, 16:43
Wohnort: Dortmund

Hallo zusammen

Mein erstes Posting, natürlich gleich eine Frage, an der ich mir den Kopf zerbreche.
Verbindung zur MySQL-Datenbank steht, Abfrage und Anzeige auch.

ID ist eindeutiges unique Feld.
Windows10, Qt4, Python 2.7

Es geht um ein kleines Programm, mit Qt-Oberfläche zur Anzeige von Konto-Buchungsdaten.
Anzeige soweit ok, möchte nun aber über eine ComboBox Kategorien zu den einzelnen Buchungen vergeben.
Update der Kategorie und schreiben in Datenbank klappt auch.
Aber:
Ich möchte, wenn ich den Datensatz mit der eindeutigen ID, z.B. "186", geändert und gespeichert habe,
diesen Datensatz mit dieser ID (und der aktuellen Kategorie) aktualisiert anzeigen. Auch wenn ich mal über
die beiden Button "vor" und "zurück" durch die Ergebnismenge von fetchall steppe.

Ich könnte das Abfrageergebnis mit "reihe = cursor.execute(sql)" aktualisieren.
Dann würde wieder der erste Datensatz angezeigt werden. Es soll aber der gerade geänderte wieder angezeigt werden.

Also wie bekomme ich aus meiner Abfragemenge (Liste der Datensätze) wieder den Datensatz mit der ID "186" vorgesetzt, sprich lokalisiert?
Muss ich manuell durch die Ergebnismenge der Abfrage iterieren bis ich ID gefunden habe? Oder geht das auch anders?

Code: Alles auswählen

	db = pymysql.connect("localhost","root","aktPW","di" )
	cursor= db.cursor()
	sql = "SELECT datum, vz,ag,bt,kat,betrag,saldo,id,info FROM ba ORDER BY id DESC LIMIT 50" 
	reihe = cursor.execute(sql)
	results = cursor.fetchall()
und steppe durch die Datensätze mit

Code: Alles auswählen

def nachsterDatensatz():
	global reihe
	global i
	if i < reihe-1:
		i = i + 1
		anzeige()
		
def vorherigerDatensatz():
	global reihe
	global i
	if i > 0 :
		i = i -1
		anzeige()
		
def anzeige():
	global i
	#datum, vz,ag,bt,kat,betrag,saldo,id,info
	w.lineEdit1.setText(str(results[i][0])) #datum
	w.lineEdit2.setText(str(results[i][1]))	#vz
	w.lineEdit3.setText(str(results[i][2]))	#ag
	w.lineEdit4.setText(str(results[i][3]))	#bt
	w.lineEdit5.setText(str(results[i][4]))	#kat
	w.lineEdit6.setText(str(results[i][5]))	#betrag
	w.lineEdit7.setText(str(results[i][6]))	#saldo
	w.Label1.setText(str(results[i][7]))	#ID
	w.lineEdit8.setText(str(results[i][8]))	#info
	w.comboBox1.setEditText(str(results[i][4]))	#kat
Unter Delphi sah das Ganze so aus:

Code: Alles auswählen

procedure THauptformular.EditFuellen(id:string);
var
  SearchOptions: TLocateOptions;
begin
  SearchOptions := [loPartialKey];
  query.Locate('ID',id,SearchOptions);
  CbbKST.Text := query.FieldByName('KST').AsString;
Ich habe dort in der Ergebnismenge der Abfrage mit query.Locate den Datensatz mit der zu suchenden ID lokalisiert und angezeigt.
Gibt es sowas wie ein cursor.Locate(ID,"186") ?

Danke für Hilfe :)
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

mir ist dein Problem nicht ganz klar... Hast du ein Problem, die ID des geänderten Datensatzes zu bestimmen und abzufragen oder hast du ein Problem, dass dein Qt Programm nach der Änderung nicht den Datensatz anzeigt, den du gerne hättest, sondern den z.B. ersten?

Gruß, noisefloor

Edit -Nachtrag: wenn du `global` verwendest, kannst du zu 99,9% sicher sein, dass du suboptimal mit Python programmiert hast. Die Verwendung von `global` ist normalerweise nicht nötig und macht es unnötig schwer, den Programmzustand nachzuvollziehen.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst einen zweiten Cursor machen, und den dazu benutzen bei der Anzeige den aktuellen Datensatz einfach direkt aus der DB zu holen. Dann ist der aktuell.

Wenn du SQLAlchemy verwenden würdest, ginge das ähnlich leicht ableitbar wie in Delphi. Da du das nicht tust, ist es nur mit der Kopie deines SQLs machbar. Oder etwas geschickter mitbaue einbetten einer WHERE-Klausel, die für die gesamte Liste halt leer ist.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Bucket: Du schreibst, Du benutzt Qt, Dein Programm sieht aber nicht danach aus. Für GUIs (vor allem Qt) muß man zwingend Klassen schreiben. Du sortierst nach der ID und fragst nur 50 davon ab? In einem ersten Schritt würde ich gar keine Liste im Speicher halten sondern bei jeder ID eine neue Datenbankabfrage über eine ID machen. Also bei einem Schritt hoch "SELECT ... WHERE id>:old_id ORDER BY id ASC LIMIT 1" bei Schritt runter entsprechend umgekehrt.

Davor solltest Du aber lernen, wie man Funktionen schreibt; alles was eine Funktion braucht, bekommt sie über ihre Argumente, und nicht magisch von irgendeinem globalen Kontext. Dann solltest Du lernen, wie Klassen benutzt, um dann ein sauberes Qt-Programm zu schreiben.
Bucket
User
Beiträge: 2
Registriert: Montag 5. Februar 2018, 16:43
Wohnort: Dortmund

Hallo
noisefloor hat geschrieben: ... Änderung nicht den Datensatz anzeigt, den du gerne hättest, sondern den z.B. ersten?")
Genau das ist mein Problem.
noisefloor hat geschrieben: ... kannst du zu 99,9% sicher sein, dass du suboptimal mit Python programmiert hast
Stimmt, hast Recht. Ich kanns noch nicht, kommt später, hoffentlich :)

@__deets__ : SQLAlchemy ... hm kenne ich noch nicht. Werde ich mal googeln. Danke für die Tips!
Sirius3 hat geschrieben:@Bucket: Du schreibst, Du benutzt Qt, Dein Programm sieht aber nicht danach aus.
Hatte nur Teilstücke, ohne den Qt-Oberflächenaufruf, aus dem kleinen Testprogramm gepostet.
Sirius3 hat geschrieben: Für GUIs (vor allem Qt) muß man zwingend Klassen schreiben.
Hm ... Fragezeichen ... Hast bestimmt recht, muss ich lernen.
Sirius3 hat geschrieben: In einem ersten Schritt würde ich gar keine Liste im Speicher halten sondern bei jeder ID eine neue Datenbankabfrage über eine ID machen. Also bei einem Schritt hoch "SELECT ... WHERE id>:old_id ORDER BY id ASC LIMIT 1" bei Schritt runter entsprechend umgekehrt.
DAS ist in meinen Augen DIE Idee. :idea: Warum ich nicht selber drauf gekommen bin !? *BrettVorKopf*
Das Limit hatte ich in der SQL-Abfrage nur gesetzt, damit nicht alle Datensätze/Buchungen, sind schon so 12000, nur für das Testprogramm im Speicher herumgeistern.
Sirius3 hat geschrieben: Davor solltest Du aber lernen, wie man Funktionen schreibt; alles was eine Funktion braucht, bekommt sie über ihre Argumente, und nicht magisch von irgendeinem globalen Kontext. Dann solltest Du lernen, wie Klassen benutzt, um dann ein sauberes Qt-Programm zu schreiben.
Stimmt! Global ist bäh, so bin ich mit Pascal/Delphi auch vor xx-Jahren angefangen, hat sich dann aber schnell geändert.
Mit Funktionen und Klassen unter Python bin ich noch nicht vertraut, muss ich lernen.
Im Testprogramm sind mit Sicherheit noch so einige Bugs oder "so macht man das nicht", ist mein Einstiegsprogramm.
Vielleicht schaffe ich es ja, auch mit eurer netten Hilfe, es gleich von Anfang an wenigstens fast richtig zu machen.
Und die globalen fliegen als erstes raus.

Im Anhang, wie geschrieben, als schlechtes Beispiel meine ersten Versuche.

Vielen Dank!

PS: "Datei anhängen"-Funktion finde ich hier nicht (Hatte Quellcode + dem Qt4-Fenster xxx.ui gezippt) , egal, mache mal so:

Code: Alles auswählen

# -*- coding: utf-8 -*-
#
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.uic import *

import pymysql.cursors
global i 
global reihe
i = 0
reihe = 0

try:
	db = pymysql.connect("localhost","root","aktPW","di" )
	cursor= db.cursor()
	cursorTemp= db.cursor()
	cursorUpdate= db.cursor()
	sql = "SELECT datum, vz,ag,bt,kat,betrag,saldo,id,info FROM ba ORDER BY id DESC LIMIT 50" 
	reihe = cursor.execute(sql)
	results = cursor.fetchall()
	
	cursorTemp= db.cursor()
	sql = "SELECT DISTINCT kat FROM ba order by kat" 
	cursorTemp.execute(sql)
	resultsTemp = cursorTemp.fetchall()
	
except:
	print "Error: unable to fetch data"
	db.close()

def update():
	sql = "Update ba set kat = '"+ str(w.comboBox1.currentText()) +"' where ID = " +  str(results[i][7])
	cursorUpdate.execute(sql)	
	db.commit()

def anzeige():
	global i
	#datum, vz,ag,bt,kat,betrag,saldo,id,info
	w.lineEdit1.setText(str(results[i][0])) #datum
	w.lineEdit2.setText(str(results[i][1]))	#vz
	w.lineEdit3.setText(str(results[i][2]))	#ag
	w.lineEdit4.setText(str(results[i][3]))	#bt
	w.lineEdit5.setText(str(results[i][4]))	#kat
	w.lineEdit6.setText(str(results[i][5]))	#betrag
	w.lineEdit7.setText(str(results[i][6]))	#saldo
	w.Label1.setText(str(results[i][7]))	#ID
	w.lineEdit8.setText(str(results[i][8]))	#info
	w.comboBox1.setEditText(str(results[i][4]))	#kat
		
def buttonKlick():
	global i
	if i < reihe-1:
		i = i + 1
		anzeige()
		
def buttonKlick2():
	global reihe
	global i
	if i > 0 :
		i = i -1
		anzeige()
		
app = QApplication(sys.argv)
w = loadUi("oberfl.ui")

w.connect(w.Knopf,SIGNAL("clicked()"), buttonKlick)	#Datensatz vor
w.connect(w.Knopf2,SIGNAL("clicked()"), buttonKlick2) #Datensatz zurück
w.connect(w.ButtonUpdate,SIGNAL("clicked()"), update) #Änderung Kategorie übernehmen
for zeile in resultsTemp: 
	w.comboBox1.addItem(zeile[0]) # comboBox mit Liste der vorhandenen Kat füllen    Index[0] weil sonst mit (" ,")
anzeige()
w.show()

sys.exit(app.exec_())
Antworten