Erstellen eines Priem Key in Python

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
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Servus,

und wieder ich mit meinen Datenbanken :). Unten seht ihr einen Python Code mit dem ich Feeds streame und diese in eine MySQL Datenbank schreiben will. Alles klappt bis auf das erstellen des Primary Keys:

So erstelle ich die Tabelle:

Code: Alles auswählen

db = MySQLdb.connect(host="localhost", # your host, usually localhost
                     user="root", # your username - SELECT * FROM mysql.user
                     passwd="*****", # your password
                     db="python_test") # name of the data base

cur = db.cursor()
cur.execute("DROP TABLE IF EXISTS test1")

sql = """CREATE TABLE test1 (LSE_ID INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(LSE_ID), Unix_Timesstamp REAL, III_Timesstamp TEXT, Source TEXT, Title TEXT, Text TEXT,  Link TEXT, Epic TEXT, CommentNr REAL,  Author TEXT)"""
cur.execute(sql)
und so befuelle ich die Tabelle

Code: Alles auswählen

for item in feed:
        cur.execute("""INSERT INTO test1 VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)""",item)
db.commit()
In Item befindet sich der aufgesplittete Feed. Da der Feed alle 3 Minuten neu geladen wird brauche ich die Schleife. Lösche ich das LSE_ID INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(LSE_ID), Statement aus der Create Table Funktion funktioniert alles perfekt.

Grüße und danke für die tolle Hilfe hier :)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

h0rnung hat geschrieben:Lösche ich das LSE_ID INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(LSE_ID), Statement aus der Create Table Funktion funktioniert alles perfekt.
Was funktioniert denn *bei dem gezeigten Code* nicht? Das hast Du uns nicht verraten ;-)

Und Bitte formatiere doch mal Deinen SQL-String "richtig" - so erkennt man ja kaum die Struktur. (Ich würde Annotationen (wie ``PRIMARY KEY`` auch immer an den Schluss der Deklaration schreiben!).
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich nehme auch für Inserts immer

Code: Alles auswählen

INSERT INTO tabelle (bla, bli, blub) VALUES (:1, :2, :3)
dann gibt es auch keine Probleme mit den Feldern.
BlackJack

Sicher nicht das eigentliche Problem, aber Unix-Zeitstempel und Kommentarnummern als REAL? Really? :-D
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Also was nicht klappt ist das Erstellen eines Primar Keys in Form einer fortlaufenden Nummer. Ich habe versucht diesen PrimKey mit folgendem Statement zu erstellen: LSE_ID INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(LSE_ID),, leider kommt dann aber immer folgender Fehlercode:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:/Python27/MySQL_finalversion/rss_db_connection_mysql_v1.py", line 53, in <module>
    main()
  File "C:/Python27/MySQL_finalversion/rss_db_connection_mysql_v1.py", line 47, in main
    cur.execute("""INSERT INTO test1 VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)""",item)
  File "C:\Python27\lib\site-packages\MySQLdb\cursors.py", line 205, in execute
    self.errorhandler(self, exc, value)
  File "C:\Python27\lib\site-packages\MySQLdb\connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
OperationalError: (1136, "Column count doesn't match value count at row 1")
Lösche ich LSE_ID INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(LSE_ID), aus meinem Code raus, dann funktioniert alles perfekt - daraus schliesse ich, dass das statement nicht stimmt :)

So verständlicher :P ..Danke und Gruss
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

@BlackJack: Absoluter Noob hier am Werk. Jeder Hinweis ist ein guter - Vorschläge zu meinen Datentypen?
BlackJack

@h0rnung:Du hast eine Tabelle mit 10 Werten und versuchst mit Deinem INSERT da 9 Werte einzufügen. Das geht natürlich nicht. PRIMARY KEY bedeutet *nicht* das man dafür keine Werte angeben muss oder darf wenn man *diese* Form des INSERT verwendet. Wenn man zum Beispiel eine Sicherung der Daten wieder in eine Tabelle zurück spielen will, dann will man ja auch den Primärschlüssel mit eintragen. Die Lösung hat Sirius3 ja schon gezeigt. Wenn man die Spalten explizit angibt, kann man auch welche Auslassen. Zum Beispiel den Primärschlüssel.

REAL sind Gleitkommazahlen. Klassische Unix-Zeitstempel sind Ganzzahlen in Sekunden. Wenn Du da noch Nachkommastellen hast, dann könnte REAL eventuell Sinn machen, oder man sorgt dafür das der Zeitstempel als Ganzzahl gespeichert wird, zum Beispiel in dem man ihn in Millisekunden umrechnet. Kommentarnummern sind ja wohl sehr Wahrscheinlich keine Gleitkommazahlen.
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Verstanden danke :)

Zum eigentlichen Thema. Ich habe das ganze Problem bereits mit dem SQLite3 Modul von Python bearbeitet und erfolgreich gelöst:

Code: Alles auswählen


connection = sqlite3.connect('LSE_duotucuM.db')
pointer = connection.cursor()
pointer.execute("CREATE TABLE tabelle(Key INTEGER PRIMARY KEY AUTOINCREMENT, Unix_Timesstamp REAL, III_Timesstamp TEXT, Source TEXT, Title TEXT, Text TEXT,  Link TEXT, Epic TEXT, CommentNr REAL,  Author TEXT)")

[..........]

for item in feed:
        pointer.execute("INSERT INTO tabelle(Unix_Timesstamp, III_Timesstamp, Source, Title, Text, Link, Epic, CommentNr, Author) VALUES(?,?,?,?,?,?,?,?,?)",item)
connection.commit()
Hier funktioniert es eben genau so, dass man beim Insert befehlt den Primary Key weglässt, da die nötige Logik bereits beim Create Befehl übergeben wird.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

h0rnung hat geschrieben:Verstanden danke :)
...
Hier funktioniert es eben genau so, dass man beim Insert befehlt den Primary Key weglässt, da die nötige Logik bereits beim Create Befehl übergeben wird.
Entweder hast Du es noch *nicht* verstanden, oder aber nicht genau hingeguckt! ;-)

Dein ``INSERT`` macht hier ja eben *genau das*, was Sirius3 Dir gezeigt hat...

Dass ein Schlüssel automatisch erzeugt wird, ist dabei zunächst einmal egal.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Ich habe es nicht verstanden :? ... habe hier nochmal meinen kompletten Code beigefügt. Mein Problem ist, dass eine Liste bestehend aus Listend übergeben wird und da hängts bei mir. Was Sirius3 meint ist mir klar - wie ich es umsetzen soll gänzlich unklar.

Code: Alles auswählen

import feedparser
import urllib2
import cookielib
import MySQLdb
import time
import datetime
from cookielib import CookieJar
from urllib2 import urlopen


db = MySQLdb.connect(host="localhost", # your host, usually localhost
                     user="root", # your username - SELECT * FROM mysql.user
                     passwd="test", # your password
                     db="sentiment_analysis") # name of the data base

cur = db.cursor()
cur.execute("DROP TABLE IF EXISTS feeddata_lse")

sql = """CREATE TABLE feeddata_lse (LSE_ID integer NOT NULL AUTO_INCREMENT, Unix_Timesstamp REAL, III_Timesstamp TEXT, Source TEXT, Title TEXT, Text TEXT,  Link TEXT, Epic TEXT, CommentNr REAL,  Author TEXT, PRIMARY KEY(LSE_ID))"""
cur.execute(sql)

def feed_load(feed):
    return [(time.time(),
             entry.published,
             'lse',
             entry.title,
             entry.summary,
             entry.link,
             (entry.link.split('?ShareTicker=')[1]).split('&post=')[0],
             entry.link.split('&post=')[1],
             entry.author)
            for entry
            in feedparser.parse(feed).entries]
     
def main():
    FEED_URL = "http://www.lse.co.uk/chat/recent/"
    feed = feed_load(FEED_URL)

    print feed[1][0]
    
    for item in feed:
        cur.execute("""INSERT INTO feeddata_lse VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)""",item)
    db.commit()

if __name__ == "__main__":
    while True:
        main()
        time.sleep(10)
BlackJack

@h0rnung: Vergleich doch noch mal den INSERT-Befehl zwischen dem was nicht funktioniert und dem was funktioniert. Die sind von der Struktur her doch *deutlich* unterschiedlich.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du musst beim ``INSERT``-Befehl nur genau *die* Attribute angeben, welche dann auch eingefügt werden. Da Du für das Attribut mit dem PK *keinen* Wert angeben willst (eben, weil dieser automatisch erzeugt werden soll), musst Du *explizit* alle Attribute benennen, für die Du Daten einfügen willst.

Lässt Du diese Angabe weg - wie aktuell bei Dir - so will die DB-Engine auch Daten für *alle* Attribute, also inklusive des Feldes mit dem PK. Für dieses stellst Du aber keine Daten bereit und darum kommt es zum Fehler.

So schwer ist das eigentlich nicht...

Im übrigen sind das *keine* Python-Probleme. Du könntest das Statement 1:1 in einer SQL-Shell testen - vielleicht wird Dir das dann klarer...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Folgende Lösung habe ich gesucht und gefunden: Herzlichen Dank für die Hilfe!

Insert Befehl (vgl. oben):

Code: Alles auswählen

INSERT INTO feeddata_lse(Unix_Timesstamp, III_Timestamp, Source, Title, Text, Link, Epic, CommentNr, Author) VALUES (%s,%s, ...
so klappt's :mrgreen:
Antworten