C: MYSQL_ROW in Zeichenketten umwandeln

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo miteinander,

    Hintergrund: Die Datensätze aus der Datenbank im RPi sollen auf eine Datenbank bei einem Webhoster repliziert werden.
    Tabellenschema:

    Code
    CREATE TABLE `events` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `gpio_id` tinyint(3) unsigned NOT NULL,
      `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

    Prinzipielles Vorgehen: Abfrage der remote_db: last_id="SELECT MAX(id) FROM events"
    local_db: "SELECT * FROM events WHERE id>last_id". Für jedes Ergebnis soll dann ein INSERT in die remote_db erfolgen.

    Problem: Das Ergebnis durch MYSQL_ROW liegt in einem speziellen Format vor. Etwa so:
    id NULLBYTE gpio_id NULLBYTE event_time NULLBYTE.
    Wobei die Felder jeweils Zeichenketten sind, egal welches Datenbank-Format definiert ist.

    Für die Abfrage "SELECT MAX(id) FROM events" konnte ich das Problem noch lösen durch

    Code
    MYSQL_ROW  row, last_remote_id;
    char last_id[12];
    ...
    last_remote_id = mysql_fetch_row (mysql_res);
    char select[] = {"SELECT * FROM events WHERE id>"};
    sprintf(last_id,"%s",last_remote_id[0]);
    size_t len = MAX - strlen(select)+1;
    strncat(select, last_id, len);


    da dass Ergebnis in diesem Fall nur ein Feld lang ist.
    Wie bekomme ich dass bei "SELECT * FROM events" hin, dass dann 3 Felder umfasst. Also jedes Feld in eine Variable vom Typ char zu packen?

  • Hi mbrod,
    so trifft man sich wieder ;) ...

    hmmm ... entweder ich bin noch nicht ganz wach oder ich verstehe das jetzt nicht so recht.
    Ist vermutlich auch nicht so einfach zu beschreiben und klingt irgendwie kompliziert.

    Kannst Du das Problem nicht einfach über einen Export/Import lösen?
    Wenn nicht, dann wären gaube ich weiterführende Infos ganz hilfreich ...

    Schönen Tag noch,
    -ds-

  • Ich hatte nicht erwähnt, dass die Datenbank des RPis zum Zählen von Impulsen per GPIO eines Stromzählers verwendet werden soll.
    Export/Import scheint mir da keine Lösung zu sein, denn pro Kilowattstunde fallen tausend Datensätze an. Export/Import verstehe ich immer als Gesamtmenge einer Tabelle, die ja nach z.B. einem Jahr schon erheblich sein kann, besonders wenn man möglicherweise alle 8 GPIOs (=8 Zähler) verwenden würde.

    Ich stelle mir vor, die externe Datenbank (remote_db) per cronjob so alle 15 Minuten zu aktualisieren. Dort auch die Visualisierung zu realisieren, sodass sie für alle Interessierten (ggf. per login) per Internet zugänglich ist. So hätte man auch eine Sicherheitskopie.

    In C bin ich halt Neuling. Mit Python habe ich auch null Erfahrung. In PHP hätte ich das wahrscheinlich ruckzuck gelöst. Die Behandlung von Zeichenketten in C ist ja schon arg umständlich. (Stringverkettung in PHP einfach nur ein Punkt.)

    Als Webserver scheint der RPi ja nicht so performant zu sein. Was man so liest. Aber für einen cronjob alle Viertelstunde, sollte es wohl reichen, kommt mir gerade so die Idee.

    Vielleicht sollte ich doch mal Apache und PHP installieren.
    Was meint ihr?

    Einmal editiert, zuletzt von mbrod (29. Juli 2013 um 22:22)

    • Offizieller Beitrag

    kannst du mir mal mal nen testdatensatz posten? dann kann ich dir morgen früh ein beispiel in python posten. Sollte für dich als php'ler kein problem sein das zu adaptieren.

    Edit: wenn du wirklich den php weg gehen willst, nimm lighthttpd, is deutlich performanter.

  • local_db:

    SQL
    SELECT * FROM events WHERE id>1337


    würde z.B. liefern:

    id gpio_id event_time
    1338 1 27.07.2013 11:26:08
    1339 1 27.07.2013 11:26:10
    1340 1 27.07.2013 11:26:12
    1341 1 27.07.2013 11:26:14
    1342 1 27.07.2013 11:26:17

    Das Ergebnis würde ja zeilenweise verarbeitet werden. Also im Prinzip so:

    Code
    while(row_local){
        mysql_query(remote_db, "INSERT INTO events (id,gpio_id,event_time) 
           VALUES (row_local[id],row_local[gpio],row_local[event_time])"
    }


    row_local wäre ein assoziatives Array, wenn die MySQL-Python-API so etwas bereitstellt. Die Syntax in dem Beispiel ist natürlich nicht valide (in welcher Sprache auch?), sondern soll nur das Prinzip verdeutlichen.

  • Ja hallo ...

    Hmm ... das ist so was, für ich vor einigen Monaten für mein Brüderlein gemacht habe (1000 Impulse / Stunde / kWh). Damals hatte er mir den RPi in die Hand gedrückt und dadurch überredet und angefixt ;) ...

    Nun - kleiner Tipp von mir: nimm in Deine Tabelle noch ein Feld mit Uhrzeit und Datum im Klartext auf - das erleichtert das Testen und Auffinden von Daten ungemein ... die Timestamps sind so schwer zu verstehen ;)

    Mir würde da Folgendes dazu einfallen:
    Du hast eine Remote-DB. Mit PHP kannst Du problemlos sowohl auf Deine Remote-DB als auch auf Deine lokale DB zugreifen.
    Über cron kannst Du auch einen PHP-script starten.
    Wenn Du nun in Deiner lokalen DB noch eine Tabelle anlegst, in der Du Dir die letzte Timestamp merkst, die Du in Deine Remote-DB hochgeladen hast, kannst Du einfach mittels select ... where Timestamp > UploadTimestamp die Datensätze holen und per fetch und insert in die Remote-DB einfügen.

    Nur mal so als Denkanstoss ...

    Das ginge natürlich genauso gut in C - und das ist überhaupt nicht umständlich ;) ...

    Ach ja: Auswertung auf dem RPi würde ich nicht machen. Ich habe das mal probiert mit grafischer Aufbereitung, Ändern der Granularity (also stunden-, tage-, wochenweise ...) - da ist die Handy-CPU mit überfordert. Die bekommt schon mit phpmyadmin Schluckauf. Deshalb nehme ich für DB-Management MySQL Administrator - der läuft lokal auf meinem Laptop und steuert die DB übers Netz.

    cheers,
    -ds-

  • So, habe nun die Replikation der lokalen Datenbanktabelle nicht mit C sondern mit PHP realisiert. Dazu habe ich lighttpd installiert.


    Wenn Du nun in Deiner lokalen DB noch eine Tabelle anlegst, in der Du Dir die letzte Timestamp merkst, die Du in Deine Remote-DB hochgeladen hast, kannst Du einfach mittels select ... where Timestamp > UploadTimestamp die Datensätze holen und per fetch und insert in die Remote-DB einfügen.


    Das habe ich über das Feld id erledigt, welches bei jedem neuen Datensatz hochzählt. Man fragt die entfernte Datenbank nach MAX(id) ab und die lokale DB dann alle Datensätze, die größer als MAX(id) sind. Diese werden per INSERT in die entfernte Datenbank übertragen.

    Einmal editiert, zuletzt von mbrod (1. August 2013 um 21:08)

Jetzt mitmachen!

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