I happened to notice last night that db_affected_rows() is the number of matched rows in the WHERE clause, not the number of rows that were actually changed.  So (maybe only in drupal) if the data is the same these count as "affected" rows.

If you grep core for db_affected_rows you see that the logic is
  db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'",
  if (!db_affected_rows()) {
    @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')",
  }


--mark

On Mon, Mar 31, 2008 at 9:13 AM, Earnie Boyd <earnie@users.sourceforge.net> wrote:
Quoting John Fiala <jcfiala@gmail.com>:

> On Mon, Mar 31, 2008 at 6:43 AM, Lluís <enboig@gmail.com> wrote:
>> I need to save a value inside a table; I think the best/fast way of
>> doing so is:
>>
>
> Personally I like to keep track internally if a row's been saved to
> the db or not - but I've seen some folks try the UPDATE statement,
> call db_affected_rows to see if any rows were changed, and if none
> were, to do the insert.

Doesn't work if data is the same; no rows will be updated and
db_affected_rows will return 0.  The method the OP used is correct
insert else update.