Variable in Python von str zu int

  • Hallo vor dem Jahreswechsel soll mein Pi endlich das loggen in Datenbanken erlernen.
    Dazu fehlt mir aber noch die Möglichkeit einen vermeintlichen Integer Wert der leider als String in der Variable abgespeichert wird , auch in Integer umzuwandeln damit ich ihn in die DB bekomme

    ich habe schon versucht mit int(values[0]) den String zu Integer zu machen aber das scheint nichts genützt zu haben.

  • > int(values[0])
    Falsche Loesung fuer das falsche Problem!

    Diese Zeile wandelt values[0] in einen int um und vergisst ihn dann wieder...

    values[0] ist bereits ein int und genau das ist das Problem.

    So funktioniert wenigstens die String concatenation:

    Code
    cur.execute("INSERT INTO \"Zeiten\" (\"Timestamp\", \"Wert\") Values(now(),"+str(values[0])+")")
  • Eigentlich ganz einfach... Du musst das in eine Variable so hinterlegen wie du es brauchst.

    values[i] = mcp.read_adc(i)

    Änderst du einfach in

    values[i] = int(mcp.read_adc(i))

    ab. Die Zeile danach kannst du dir schenken, die bewirkt nichts oder zumindest nicht das was du willst: int(values[0])

    cur.execute("INSERT INTO \"Zeiten\" (\"Timestamp\", \"Wert\") Values(now(),"+values[0]+")");

    Das brauchst du so aber auch nicht schreiben. Mach es lieber so:

    cur.execute("INSERT INTO Zeiten (Timestamp, Wert) VALUES (now(), %s)", (values[i],))

    values[0] machte da eigentlich eh kein Sinn, oder deine for Schleife macht kein Sinn.... Ansonsten stellt sich nämlich die Frage wieso du zuvor values[i] = ... setzt.

  • danke euch zweien! meigrafd dein Skript raff ich irgendwie überhaupt nicht!
    nutze ich :
    cur.execute("INSERT INTO Zeiten (Timestamp, Wert) VALUES (now(), %s)", (values[i]))
    erhalte ich die Fehlermeldung:
    TypeError: 'int' object does not support indexing

    Nutze ich hingegen folgendes:
    cur.execute("INSERT INTO \"Zeiten\" (\"Timestamp\", \"Wert\") Values(now(),"+values[0]+")");
    erhalte ich folgende Fehlermeldung:
    TypeError: cannot concatenate 'str' and 'int' objects
    -bash: TypeError:: Kommando nicht gefunden.

    die Spalte Wert ist numeric(5,2) und der Wert ist 316 sollte doch also klappen?!

  • Naja, das gesamte Konstrukt ist komisch... Da sind die Fehlermeldungen fast nebensächlich.

    [code=php]
    import time
    import os
    import psycopg2
    import Adafruit_MCP3008

    CLK = 21
    MISO = 19
    MOSI = 20
    CS = 16

    conn = psycopg2.connect(database="pi_DB", user="*********", password="*********", host="192.168.178.29", port="5432")
    cur = conn.cursor()

    mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI)

    while True:
    values = [0]*8
    for i in range(8):
    values[i] = mcp.read_adc(i)
    print values[i]
    cur.execute("INSERT INTO Zeiten (Timestamp, Wert) VALUES (%s, %s);", (int(time.time()), values[i]))
    conn.commit()
    print "Daten gespeichert"
    time.sleep(60)
    [/php]

  • die Spalte Wert ist numeric(5,2) und der Wert ist 316 sollte doch also klappen?!

    Der Grund fuer das nicht-klappen ist, dass die Execute-Methode *IMMER* ein Tupel haben moechte. Genauso wie ein fetch* auch *IMMER* ein Tupel pro Zeile liefert.

    Wenn du also nur einen Wert hast, dann musst du den zu einem einelementigen Tupel machen:

    Code
    cursor.execute("STATEMENT", (wert,))

    Man beachte das Komma hinter "wert". Das macht aus "wert" das Tupel (wert,). Die Klammern dienen nur zur Eindeutigkeit - sonst waere wert wieder nur ein direkter Parameter.

    Im Inteprerter kannst du mal damit spielen:

    Code
    deets@paleale GstTest (master)]$ python
    Python 2.7.10 (default, Jul 30 2016, 18:31:42)
    >>> 10,
    (10,)
  • @danke noch mal an alle für ihre Mühen aber leider funzt es noch immer nicht!
    Ich habe mal folgendes getestet:
    in pgadmin ein Editor für Postgresql habe ich mal den Insert eingegeben:
    Nur diese Variante läuft:

    INSERT INTO "Zeiten" ("Timestamp", "Wert") VALUES(now(),111.11)
    sprich die Tabelle und die Spalten müssen in "" stehen. WARUM? weiß ich nicht dazu kenne ich mich noch zu wenig mit Postgresql aus.

    also Skript wieder umschreiben:

    cur.execute("INSERT INTO \"Zeiten\" (\"Timestamp\", \"Wert\") VALUES (%s, %s);", (int(time.time()), values[i]))

    wenn ich also das Skript von meigrafd anpasse habe ich aber ein Problem mit dem Zeitstempel

    Fehlermeldung:
    Traceback (most recent call last):
    File "temp_wakue.py", line 35, in <module>
    cur.execute("INSERT INTO \"Zeiten\" (\"Timestamp\", \"Wert\") VALUES (%s, %s);", (int(time.time()), values[i]))
    psycopg2.ProgrammingError: FEHLER: Spalte »Timestamp« hat Typ timestamp without time zone, aber der Ausdruck hat Typ integer
    LINE 1: ...NSERT INTO "Zeiten" ("Timestamp", "Wert") VALUES (1483184217...
    ^
    HINT: Sie müssen den Ausdruck umschreiben oder eine Typumwandlung vornehmen.


    Ich bin verwirrt! verhält sich bei euch Postgresql genauso? sollte ich vielleicht nicht doch wieder den Zeitstempel mit der Funktion now() setzen lassen?

  • Google einfach mal nach: psycopg2.ProgrammingError: Timestamp hat Typ timestamp without time zone, aber der Ausdruck hat Typ integer

    Deine "timestamp" Spalte ist nicht wirklich ein "unix timestamp" im direkten sinne - was ich aber annahm.

  • Hi,


    Nö, da bin ich und meine Kollegen anderer Meinung :fies:

    Noch jemand einer anderen Meinung? Wer will noch mal wer hat noch nicht :fies:

    Ich :)

    Wie immer, kommt drauf an...

    • Wenn Sender und Datenbank (sicher) in der gleichen "Zeitzone" liegen, lasse ich den Zeitstempel von der DB generieren.
    • Wenn Sender und Datenbank (potentiell) in unterschiedlichen "Zeitzonen" liegen, lasse ich auch den Zeitstempel von "extern" mitgeben.


    Und das beides wird einfach im Trigger (MySQL) kombiniert:

    Code
    IF new.`timestamp` = 0 OR new.`timestamp` IS NULL THEN 
           SET new.`timestamp` = UNIX_TIMESTAMP(); 
       END IF;

    Jeder Sender entscheidet dann, ob er den Zeitstempel mitschickt oder nicht.

    Achtung: Das Konzept geht davon aus, dass die Genauigkeit von 1 sec. ausreicht, Netzwerklatenz, Serverauslatung etc.
    Wenn höhere Genauigkeit bei der Erfassung von "Messwerten" notwendig ist, z.B. auf Millisekunden, dann immer den Zeitpunkt des "Ereignisses" extern mitgeben!

    Knut

    PS. Ich habe auch Situationen, wo Sender und DB wenige Meter entfernt sind (IoT), es aber zu Verbindungsabbrüchen kommen kann.
    Die Daten werden in dem Falle mit Zeitstempel im Dateisystem gepuffert und später korrekt nachgeladen.

  • Es gibt durchaus gute Gruende, die DB zur Zeitstempel-Generierung heranzuziehen - naemlich wenn man alle Zeitstempel einer Transaktion garantiert gleich haben moechte. "now()", "sysdate()" etc liefern naemlich innerhalb einer Transaktion immer den gleichen Wert. Lege ich also mehrere Zeilen mit Zeitstempeln an, die konzeptionell gleichzeitig sind - dann ist es von Vorteil, das die DB erledigen zu lassen. Ein Gegenargument - einfach immer den gleichen Zeitstempel von *aussen* reinzugeben - ist simpel bei den hier diskutierten 20-Zeilen-Skripten. Nicht so sehr bei mehrere 10K grossen Projekten, in denen verschiedenen Subsysteme innerhalb zB eines HTTP-Requests auf der DB arbeiten.

    Will ich allerdings einen Sensor auslesen, bei dem es mir darauf ankommt, dass ich die Zeitpunkte insbesondere relativ zueinander praezise erfasse, dann generiere ich den Zeitstempel an der Stelle, wo ich den Sensor auslese, und verarbeite danach immer dieses Paar an Informationen.

  • Hallo Jungs eure Argumente sind alle richtig aber ich möchte dabei bleiben das der Client den Zeitstempel mitschickt.
    Aber nun noch mal zurück zu der Tabelle an sich:
    [Code]
    CREATE TABLE "Zeiten"
    (
    "Timestamp" timestamp without time zone,
    "Wert" numeric(5,2)
    )
    WITH (
    OIDS=FALSE
    );
    ALTER TABLE "Zeiten"
    OWNER TO postgres;
    [\Code] und wenn ich das richtig sehe habe ich hier einen wahren Timestamp nur ohne Timezone.


  • Hallo Jungs eure Argumente sind alle richtig aber ich möchte dabei bleiben das der Client den Zeitstempel mitschickt.
    Aber nun noch mal zurück zu der Tabelle an sich:

    Code
    CREATE TABLE "Zeiten"
    (
      "Timestamp" timestamp without time zone,
      "Wert" numeric(5,2)
    )
    WITH (
      OIDS=FALSE
    );
    ALTER TABLE "Zeiten"
      OWNER TO postgres;

    und wenn ich das richtig sehe habe ich hier einen wahren Timestamp nur ohne Timezone.

    Ein "wahrer" Timestamp ? :s Ein "wahrer" wäre eine einfache Zahl... Die Sekunden die seit dem 1.1.1970 vergangen sind (epoch), wie zum Beispiel: 1483199416

    Wenn ich eine SQL Tabelle erstelle nutze ich für solch einen 'Unix Timestamp' als Type => INT(11)

    time.time()
    liefert eine float-Zahl, also mit Komma Stelle und wäre kein gültiger Eintrag für INT(11). Deshalb auch mein oben gezeigter int(time.time())

    Ich kenne mich mit postgresql nicht direkt aus, würde aber behaupten das es auch dort wie üblich unterstützt wird. http://stackoverflow.com/a/22972434

  • meigrafd sorry ich kenne aus der Microsoft Welt die Unix Thematik nicht. Da gibt es nicht das seit 1.1.1970 sondern dort gibt es Timestamp also einfach Datum + Zeit . Je nach Sprache ändert sich dann die Darstellung. Ich versuch mal herauszufinden wie das bei postgresql ist.

  • In Postgres gibt es vernuenftige TIMESTAMP-Typen, und die sollte man natuerlich auch benutzen. zB um mit verschiedenen Zeitzonen und Dingen wie Sommer/Winterzeit umgehen zu koennen. Der UNIX-Timestamp ist in dieser Beziehung praehistorisch und nicht der richtige Typ.

  • So Jungs jetzt habe ich auch endlich mal Zeit hier die Lösung zu posten:

    Code
    cur.execute("INSERT INTO \"Zeiten\" (\"Timestamp\", \"Wert\") VALUES( Timestamp \'"+ strftime("%Y-%m-%d %H:%M:$S+02", gmtime()) +" \',"+ str(values[0])+")");


    Damit bekomme ich die Werte in eine Postgresql Datenbank gespeichert.

    Eine Frage hätte ich da aber noch lässt man jetzt das Pythonskript ewig laufen, sozusagen als Prozess oder lässt man es ausführen beenden und später wieder neustarten usw. ??
    Was ist der bessere Weg?

    Einmal editiert, zuletzt von tutter (27. Januar 2017 um 18:47)

  • Wenn du in Python doppelte Anfuehrungszeichen im String haben willst, kannst du entweder einfache benutzen - also 'ich bin ein Text mit "einem Zitat"'. Weil aber einfache Anfuehrungszeichen auch wichtig in SQL sind, ist wahrscheinlich ein triple-quote besser:

    """INSERT INTO "Zeiten" ( "Timestamp" ..."""

    Ich denke allerdings, dass du die eh nicht brauchst - die sind eigentlich nur notwendig, wenn die Spaltennamen sonst uneindeutig sind. ZB wenn eine Spalte "select" heisst, dann weiss SQL nicht, ob das nun der Spaltenname, oder ein Sub-statement ist. Also muss man doppelt anfuehren.

    Dann ist dein Stringzusammengestoppel nicht so gut. Im allgemeinen verwendet man eher string-formatting, also

    "Etwas Text mit einer variablen {}".format("Stelle")

    Konkret bei SQL ist das aber eh der falsche weg, man benutzt stattdessen die Platzhalter-Version.

    cur.execute("INSERT INTO TABELLE VALUES (%s, %i)", (wert1, wert2))

    Bei nur einem Wert

    cur.execute("INSERT INTO TABELLE VALUES (%s)", (wert1,))

    Man beachte das Komma. Dieses Vorgehen ist wichtig, weil man so zum einen SQL-injections vermeidet, die durch Usereingaben entstehen koennen, und zum zweiten dem Execution Planer der Datenbank das Leben leichter, und die Ausfuehrung damit schneller macht.

    Und zu guter Letzt zu deiner Frage... es haengt davon ab. Natuerlich kann man einen Service bauen, der bestaendig laeuft, auch am Leben erhalten wird, wenn er zB durch Absturz stirbt.

    Man kann aber auch einen cronjob bemuehen. Was nun das richtig ist, haengt von der Anwendung ab. Viele Daten in hoher Frequenz zu schreiben spricht eher fuer den dauerhaften Prozess. Regelmaessig, aber in grossen Abstaenden eher fuer cron. Und wenn du zB auf GPIO-Eingaben wartest, musst du eh dauerhaft laufen.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!