autsch, troubles mit NULL

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Gast

hallo,

das kennen ia einige von euch:
http://www.python-forum.de/viewtopic.php?t=3064

nun gibt es im eingabefenster folgende funktion:

Code: Alles auswählen

    def get_entries(self):

        #Eintraege holen
        entries=[element.get() for element in self.entrylist]

        #Leerzeichen muessen ersetzt werden
        for i in range(len(entries)):
            test=entries[i].find(" ")
            if test and test !=-1:
                entries[i]=entries[i].replace(entries[i][test],"/")
       
       #Felder in der Eingabemaske zurucksetzen        
        for element in self.entrylist: element.delete(0,"end")


        #Eintraege in "" setzen      
        entries=[entries[i].replace(entries[i],'"'+entries[i]+'"')
                      for i in range(len(entries))]

        #Liste zu String ", "einfuegen
        s_entries=", ".join(entries)
        
        hf.tablewrapper.insertTableColumnsData(hf.db_table,hf.s_cols_names,s_entries)
        hf.list_data(result=hf.tablewrapper.getTableColumnsData(hf.s_cols_names,hf.db_table))
s_entries koennte also dann z. b. so aussehen:
"vorname", "name", "2005.11.11", "2", "2005.12.12", "3"

das problem ist ganz konkret: vorname und name kenne ich, die prüfungsdaten und entsprechenden noten, die ich eingeben möche aber natürlich noch nicht, also müsste s_entries eigentlich so aussehen

"vorname", "name", NULL, NULL, NULL, NULL

heisst, ich will nicht vorher pseudodaten eingeben, sondern die entsprechenden felder bei der eingabe einfach leerlassen können.
die tabelle unterstützt NULL, nur wie krieg ich so eine anweisung hin???

vielen dank im voraus

rolgal
BlackJack

rolgal hat geschrieben:

Code: Alles auswählen

        #Leerzeichen muessen ersetzt werden
        for i in range(len(entries)):
            test=entries[i].find(" ")
            if test and test !=-1:
                entries[i]=entries[i].replace(entries[i][test],"/")
Ach Du meine Güte. Hier wird völlig unnötigerweise ein Index `i` benutzt, anstatt einfach über die Liste der Einträge zu iterieren. Dann ist da die ``if``-Abfrage mit dem scheinbar überflüssigen `test` vor dem ``and``. Das ist aber nicht nur "komisch" sondern produziert wohl auch einen Fehler, nämlich dann wenn das erste Zeichen ein Leerzeichen sein sollte, ergibt die Bedingung `False`!

Die letzte Zeile ist dann richtig konfus. Erst wird der Eintrag von Index `i` geholt, und daraus dann ein Leerzeichen an der Position `test` -- das ist immer ein Leerzeichen, sonst würde die Zeile nicht ausgeführt, also hätte man das auch einfach als ' ' hinschreiben können.

Oder eben als Einzeiler:

Code: Alles auswählen

entries = [entry.replace(' ', '/') for entry in entries]

Code: Alles auswählen

        #Eintraege in "" setzen      
        entries=[entries[i].replace(entries[i],'"'+entries[i]+'"')
                      for i in range(len(entries))]
Das hier ist ähnlich "komisch". So ein `replace()` sucht das erste Argument in der Zeichenkette. Die Zeichenkette selbst suchen zu lassen ist ziemlich witzlos weil man weiss das sie 1. in sich selbst enthalten ist und 2. bei Index 0 anfängt und Index len(s)-1 aufhört:

Code: Alles auswählen

entries = ['"' + entry + '"' for entry in entries]
Oder mit dem Ersetzen der Leerzeichen kombiniert:

Code: Alles auswählen

entries = ['"' + entry.replace(' ', '/') + '"' for entry in entries]
das problem ist ganz konkret: vorname und name kenne ich, die prüfungsdaten und entsprechenden noten, die ich eingeben möche aber natürlich noch nicht, also müsste s_entries eigentlich so aussehen

"vorname", "name", NULL, NULL, NULL, NULL

heisst, ich will nicht vorher pseudodaten eingeben, sondern die entsprechenden felder bei der eingabe einfach leerlassen können.
die tabelle unterstützt NULL, nur wie krieg ich so eine anweisung hin???
Einfach leer lassen könnte ein Problem mit der Eindeutigkeit geben: Ist damit eine leere Zeichenkette oder ein NULL-Wert gemeint.

Wenn keine leeren Zeichenketten als Eingaben erlaubt sind, dann kannst Du einfach die Leeren Zeichenketten mit NULL ersetzen. In der erzeugten Zeichenkette zum Beispiel mit

Code: Alles auswählen

s_entries.replace('""', 'NULL')
Gast

hallo blackjack,

danke für die codekorrekturen, wenn man an etwas rumkopft und ins basteln gerät ist es gerade für hobbycoder nicht immer einfach auch noch die schönste lösung zu finden. inwieweit es notwendig ist bei der der korrektur sich nicht rein aufs sachliche zu konzentrieren sei dahingestellt.
ich bedanke mich troztdem, es leuchtet ja auch ein.

die lösung für NULL hingegen hilft nicht wirklich weiter, die idee hatte ich selber schon, bzw. ich habe NULL gleich schon am anfang einer meiner überdimensionalen schleifen eingfügt, was aber am problem nichts ändert.

eine abfrage am mysql monitor macht deutlich was ich meine:

eintrag eingegeben mit NULL am monitor sieht so aus:

Code: Alles auswählen

5 Roland Gall NULL NULL NULL NULL
mit übergebenen 'NULL', als string im code:

Code: Alles auswählen

5 Roland Gall 0000-00-00 0 0000-00-00 0
und das ist eben was ganz anderes, v.a. frage ich von einem webinterface ab ob None bzw. NULL in einem feld drinnen steht und behandle es entsrpechend, das geht aber nicht, wenn ich es so löse wie du vorgeschlagen, bzw. ich schon versucht habe.

grüße

rolgal
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich denke du müßtest einfach None nehmen.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gast

@blackjack

die sache mit -1 hatte eigentlich folgenden sinn, jetzt erst merke ich, dass es gar nicht funzt, bzw. nicht so wie ich es gedacht hatte:

bei

Code: Alles auswählen

 test="spam "
bekommt man auf

Code: Alles auswählen

test[-1]
das leerzeichen zurück.

ich wollte, dass ein allfälliges leerzeichen am ende eines eintrages nicht ersetzt wird. deshalb auch

Code: Alles auswählen

if test and test!=[-1]:
@jens: None bringt nichts, wenn es als string eingesetzt wird (selbe sache wie mit 'NULL') und als echtes None verweigert dir replace() logischerweise seine dienste

Code: Alles auswählen

    s_entries.replace('""', None)
TypeError: expected a character buffer object
grüße

rolgal
BlackJack

rolgal hat geschrieben:inwieweit es notwendig ist bei der der korrektur sich nicht rein aufs sachliche zu konzentrieren sei dahingestellt.
Äh ja, ich war wohl etwas unsachlich wenn nicht sogar unhöflich. Sorry. :oops:
die lösung für NULL hingegen hilft nicht wirklich weiter, die idee hatte ich selber schon, bzw. ich habe NULL gleich schon am anfang einer meiner überdimensionalen schleifen eingfügt, was aber am problem nichts ändert.
Was passiert eigentlich mit der Zeichenkette, die Du da zusammen baust? Wird die später genau so an die Datenbank übergeben? Verfolg das doch mal weiter.
Gast

hi blackjack,
Was passiert eigentlich mit der Zeichenkette, die Du da zusammen baust? Wird die später genau so an die Datenbank übergeben? Verfolg das doch mal weiter.
sie wird ganz genauso übergeben, ich habe es nochmal überprüft: sie geht von hier in den tablewprapper, dort wird mysqldao und die entsprechende insertfunktion aufgerufen.

edit: @blackjack:

bis ich, wir oder wer auch immer eine lösung dafür gefunden hat/haben, werde ich mal im code weitere schleifen und list compr. überarbeiten, da gibt es nämlich noch einige, dann werde ich in showcase wieder mal ein update machen....

grüße

rolgal
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Aha, ich glaube jetzt kann ich die Problematik nachvollziehen... Zumindest hab ich änlichen Ärger...

In der DB API steht:
SQL NULL values are represented by the Python None singleton on
input and output.
Also bekommt man schon mit dem Python "None" ein NULL-Eintrag in SQL hin, wie ich es geschrieben hab.

Erlaubt, in deinem Fall, das Tabellen-Feld überhaupt NULL??? Ich denke nicht! Sondern es ist wohl ein Standard-Wert gesetzt! also einmal "0000-00-00" und einmal nur "0"...

Schau doch mal in phpMyAdmin nach...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gast

hallo jens,

dass es grundsätzlich mit None geht kann schon sein.

natürlich erlauben die felder NULL, darin besteht kein zweifel.

nur 'None' bringt nichts, weil es ein string ist. wenn nun ein feld vom typ date etwas erhält was sinnlos ist, dann setzt es einen default wert. z.b. 0000-00-00

und None, also das richtige None weiss ich nicht wie ich es durchgeben soll, weil ja ein string zusammengebaut wird und string+None geht nicht.

soweit meine erfahrungen.

liebe grüße

rolgal
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

rolgal hat geschrieben:None, also das richtige None weiss ich nicht wie ich es durchgeben soll, weil ja ein string zusammengebaut wird und string+None geht nicht.
Natürlich mußt du das richtige None nehmen... Warum mußt du damit einen String zusammen bauen??? Nutzt du nicht die Escape-Funktion der DB-API ??? Baust du dir deinen SQL-Befehl selber zusammen? Dann geht das natürlich nicht, aber das sollte man auch nicht machen ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gast

hallo jens,

also ich zeig dir einfach am code wie es abläuft, vielleicht bringt uns das weiter:

folgende funktion wertet die einträge in der gui aus:

Code: Alles auswählen

    def get_entries(self):

        entries=[element.get() for element in self.entrylist]

         
        for element in self.entrylist: element.delete(0,"end")
                   
        entries = ['"' + entry.replace(' ', '/') + '"' for entry in entries]
    

        s_entries=", ".join(entries)
        
        hf.tablewrapper.insertTableColumnsData(hf.db_table,hf.s_cols_names,s_entries)
        hf.list_data(result=hf.tablewrapper.getTableColumnsData(hf.s_cols_names,hf.db_table))
und ich muss doch einen string zusammenbauen, wie soll das sonst gehen, dieser geht dann weiter über den tablewrapper, code spar ich mir, weil der nur checkt welche datenbank angesprochen wird und das entsprechende modul importiert, wir haben es in dem fall mit mysql zu tun, also führt folgende funktion das einfügen der daten aus:

Code: Alles auswählen

    def insertTableColumnsData(self,db_table,s_cols_names,entries):

        cursor=self.conn.cursor()
        cursor.execute("insert into %s (%s) values (%s)"%(db_table,s_cols_names,entries))
        self.conn.commit()
        cursor.close()
es wird also, wenn ich damit dasselbe meine, schon die escape funktion genutzt, aber um den string komme ich doch nicht herum, oder???
dass es eine lösng geben muss ist mir schon klar, sonst könnte phpmyadmin das ja auch nicht:-)

grüße

rolgal
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Anonymous hat geschrieben:

Code: Alles auswählen

cursor.execute("insert into %s (%s) values (%s)"%(db_table,s_cols_names,entries))
Nein du nutzt nicht die SQL-Escape-Funktion!!! Du machst ein ganz normales String-Operation und das übergibst du cursor.execute() Dann ist auch klar, das ein echtes None zu einem String "None" wird ;) Anders geschrieben machst du das:

Code: Alles auswählen

SQLcommand = "insert into %s (%s) values (%s)" % (db_table,s_cols_names,entries)
cursor.execute(SQLcommand)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gast

hi jens,

Code: Alles auswählen


Nein du nutzt nicht die SQL-Escape-Funktion!!! 
grummel, ich habe wohl was anderes in erinnerung, ich muss den thread von damals nochmals lesen, jedenfalls haben wir lang rumgedoktert, damit eben,.....eben was anderes.....:D

wie muss es denn richtig aussehen, und um den string in der gui anwendung komm ich wohl schlecht rum?

kannst du mir bitte weiterhelfen?

grüße

rolgal
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Schau dir mal den Thread an: http://www.python-forum.de/viewtopic.php?t=3175

Deswegen hatte ich mir ja einen Wrapper geschrieben ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gast

hallo,

ich hätte tabellars variante für postgresql nicht gleich übereifrig umschreiben sollen, damit gehts nämlich, und dann ist auch kein string vorher notwendig, im detail check ich es noch nicht ganz ab, aber ich steig sicher noch dahinter:

Code: Alles auswählen

    def insertTableColumnsData(self,colList,valueList):
        cur=self.con.cursor()       
        columns = colList
        cols = ", ".join(columns)
        value_placeholders = ", ".join(["%s"] * len(columns))
        values = valueList
        sql = """insert into tfoo (%(cols)s)
                 values (%(value_placeholders)s)""" % locals()
        cur.execute(sql, values)
        self.con.commit()
wenn ich das also für mysqlDAO anpasse und eben listen durchreiche, dann steht beim check am mysql monitor tatsächlich NULL drin.

@edit: bequemlichkeit wird zu recht bestraft: weil tabellars variante im ersten moment für mich so undurchsichtig war, habe ich das sofort umgeschrieben , zahlreiche printstatements an verschiedenen positionen in der funktion haben mir jetzt weitergeholfen zu verstehen, wie die funktion von tabellar genau arbeitet und warum es dann auch mit NULL klappt.

grüße

rolgal
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Für mich sieht das sehr umständlich aus, außerdem verwende ich generell kein locals()... Hier mal eine Version, die das selbe machen sollte:

Code: Alles auswählen

    def insertTableColumnsData(self,colList,valueList):
        sql = "insert into tfoo (%(cols)s) values (%(placeholders)s)" % {
            "cols"          = ", ".join(colList),
            "placeholders"  = ", ".join(["%s"] * len(colList))
        }
        self.con.cursor().execute(sql, tuple(valueList))
        self.con.commit()
Ich hab auch mal valueList nach tuple konvertiert. Ich weiß allerdings nicht ob das zwingend notwendig ist.

EDIT: oder einfach so:

Code: Alles auswählen

    def insertTableColumnsData(self,colList,valueList):
        sql = "insert into tfoo (%s) values (%s)" % [
            ", ".join(colList), ", ".join(["%s"] * len(colList))
        ]
        self.con.cursor().execute(sql, tuple(valueList))
        self.con.commit()

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gast

hi jens,

danke für deine beispiele, werde ich sicherlich in ruhe ausprobieren.
was das umständlich betrifft, sehe ich jetzt keine wesentliche unterschiede.
einfacher siehts nur aus, wenn man es falsch macht, wie ich es ursprünglich gemacht habe :D, lieber habe ich es aber richtig.

kurzum, auf den ersten blick, sieht mir das einfach nach einer geschmacksfrage aus, ob man deine oder tabellars version nimmt.

vielleicht sehe ich aber die tatsächlichen vorteile deiner version auch noch nicht.

bis bald

rolgal
Antworten