Theo: mysql_affected_rows zählt nicht richtig :-(

Hi,

bei mir kommt immer als Ergebnis "Doof, Zeile wurde nicht geändert", also wäre kein Datensatz betroffen gewesen. Egal, ob die Zeile durch das Script geändert wurde oder nicht.
Ist da ein Fehler im Code oder nicht?

Danke

Theo

---------------------------  CODE    -------------------------

$result=mysql_query("update tabelle set UserAktiv="1", UserLastvisit="".$Datum."" where UserName = "$Username"");
  if ($result==FALSE) {
   die(mysql_error($db));
  }

if (mysql_affected_rows($result) == 0) {
  echo ("Doof, Zeile wurde nicht geändert");
  exit;
  } else {
  echo ("Prima, Zeile wurde geändert");
   exit;
  }
------------------------------------------------------------------

  1. Halihallo Theo

    bei mir kommt immer als Ergebnis "Doof, Zeile wurde nicht geändert", also wäre kein Datensatz betroffen gewesen. Egal, ob die Zeile durch das Script geändert wurde oder nicht.
    Ist da ein Fehler im Code oder nicht?

    Die MySQL-API definiert ein Feld CLIENT_FOUND_ROWS, welches bei PHP
    wohl per default auf "FALSE" steht. Das hat den komischen
    Seiteneffekt, dass bei einem UPDATE-Statement nur jene Records
    gezählt werden, die tatsächlich geändert haben, nicht jene, die auf
    die WHERE-Clause "passen" (wie erwartet; bei CLIENT_FOUNT_ROWS=TRUE).

    Sieh mal nach, ob PHP eine Möglichkeit bietet, dieses Attribut zu
    ändern.

    Viele Grüsse

    Philipp

  2. Halihallo Theo

    Aus http://ch.php.net/manual/de/function.mysql-connect.php:

    phpweb at eden2 dot com, schrieb als Kommentar um
    28-Jun-2003 05:55 :

    <cite>
    client_flags can be things other than MYSQL_CLIENT_COMPRESS, MYSQL_CLIENT_IGNORE_SPACE and MYSQL_CLIENT_INTERACTIVE.

    I presume that mysql_connect() just passes through to the C MySQL API, which provides these constants:

    #define CLIENT_LONG_PASSWORD    1    /* new more secure passwords */
    #define CLIENT_FOUND_ROWS    2    /* Found instead of affected rows */
    #define CLIENT_LONG_FLAG    4    /* Get all column flags */
    #define CLIENT_CONNECT_WITH_DB    8    /* One can specify db on connect */
    #define CLIENT_NO_SCHEMA    16    /* Don't allow database.table.column */
    #define CLIENT_COMPRESS        32    /* Can use compression protocol */
    #define CLIENT_ODBC        64    /* Odbc client */
    #define CLIENT_LOCAL_FILES    128    /* Can use LOAD DATA LOCAL */
    #define CLIENT_IGNORE_SPACE    256    /* Ignore spaces before '(' */
    #define CLIENT_CHANGE_USER    512    /* Support the mysql_change_user() */
    #define CLIENT_INTERACTIVE    1024    /* This is an interactive client */
    #define CLIENT_SSL              2048    /* Switch to SSL after handshake */
    #define CLIENT_IGNORE_SIGPIPE  4096    /* IGNORE sigpipes */
    #define CLIENT_TRANSACTIONS    8192    /* Client knows about transactions */

    Not all of these may work or be meaningful, but CLIENT_FOUND_ROWS
    does, at least.
    </cite>

    Also: Bei mysql_(p)connect als [client_flags] einfach die "2"
    übergeben. Scheint bei dem genannten Autor funktioniert zu haben...

    Viele Grüsse

    Philipp

    1. Moin!

      Also: Bei mysql_(p)connect als [client_flags] einfach die "2"
      übergeben. Scheint bei dem genannten Autor funktioniert zu haben...

      Ja, geht aber erst ab (IIRC) PHP Version 4.3.0. Wer das Pech hat, noch mit einer 4.2er oder älter zu arbeiten, und das nicht updaten kann, der hat Pech. Oder behilft sich damit, ein TIMESTAMP-Feld in die Tabelle zu packen und im UPDATE mit "NOW()" oder "NULL" zu füllen. Dann ändert sich immer was, und die Angabe ist wieder korrekt.

      Been there, done that, have the t-shirt. ;)

      - Sven Rautenberg

      --
      "Habe den Mut, dich deines eigenen Verstandes zu bedienen!" (Immanuel Kant)
      1. Halihallo Sven und Theo

        Also: Bei mysql_(p)connect als [client_flags] einfach die "2"
        übergeben. Scheint bei dem genannten Autor funktioniert zu haben...

        Ja, geht aber erst ab (IIRC) PHP Version 4.3.0. Wer das Pech hat, noch mit einer 4.2er oder älter zu arbeiten, und das nicht updaten kann, der hat Pech. Oder behilft sich damit, ein TIMESTAMP-Feld in die Tabelle zu packen und im UPDATE mit "NOW()" oder "NULL" zu füllen. Dann ändert sich immer was, und die Angabe ist wieder korrekt.

        Jup. Wobei ich die Funktionalität nicht durch ein neues Attribut
        gewährleisten würde (etwas viel Overhead); zugegeben, es ist die
        einfachste und leider auch performanteste Lösung für alte PHP-
        Versionen.

        Dass CLIENT_FOUNT_ROWS per default "deaktiviert" ist, halte ich für
        sinnvoll. Ein SELECT-Statement liefert für mysql_affected_rows genau
        die Anzahl an Tupel, die auf die WHERE-Klause passen. Das macht
        natürlich Sinn, denn genau diese sind die "Betroffenen Datensätze".
        Was sind nun die "Betroffenen Datensätze" bei einem UPDATE? - Das
        sind eben *nicht* jene, die auf WHERE "passen", sondern die, auf
        die eine Aktion (UPDATE) ausgeführt wurde.

        @Theo: Um trotz nichtgesetztem CLIENT_FOUND_ROWS an die "passenden"
        (selektierten => SELECT) Tupel ranzukommen kannst du a) den Vorschlag
        von Sven verfolgen, oder b) einfach einen SELECT vorschieben und dort
        affected_rows auslesen. Dies braucht zwar Performance (zwei Queries),
        ist jedoch (fast) "sauber". "Fast" deshalb, da du erst bei einem
        TABLE LOCK sicherstellen kannst, dass sich zwischen den beiden
        Queries nichts geändert hat.
        Dann hättest du mehrere Informationen:
        a) die passenden Einträge (SELECT's affected rows)
        b) die geänderten Einträge (UPDATE's affected rows)
        c) die gleich gebliebenen Einträge (Differenz der beiden obigen),
           die trotz UPDATE auf status quo blieben.

        WICHTIG: Wie du siehst, ist affected_rows kein Beweis für die
        korrekte Verarbeitung des Befehls. Falls du damit eine
        Fehlerbehandlung implementieren möchtest, verwende (um Himmels
        Willen) folgendes Konstrukt:

        mysql_query(...) || die(mysql_error());
        http://www.php.net/mysql_error
        oder über Abfrage von
        http://www.php.net/mysql_errno

        so much for old PHP versions...

        Viele Grüsse

        Philipp