9

I need to update a table row IF EXISTS, otherwise INSERT a new row. I tried:

INSERT OR REPLACE INTO table VALUES ...

but if the row row exist this statement changes the row's ROWID, and that's what I'm trying to avoid (I need the rowid :D)

I also tried to find a way to get some sort of return value from the update, in the case where an update has taken place, but I still don't understand how... If I could get the return value from the update statement, I could choose wether to proceed with an insert or not.

Do you have any suggestion or solution to this problem? Or do I need to make a copy of the ROWID and use that instead of the "pure" table ROWID?

Thanks in advance, best regards

ps: I was looking HERE and I was wondering if sqlite has the OUTPUT special word too, but google didn't help me..

---- EDIT after reading comments:

table schema example

CREATE TABLE test (
    table_id TEXT NOT NULL,
    some_field TEXT NOT NULL,
    PRIMARY KEY(table_id)
)

INSERT or REPLACE INTO test (table_id, some_field) VALUES ("foo","bar")
Community
  • 1
  • 1
BeNdErR
  • 17,471
  • 21
  • 72
  • 103
  • Can you post a table schema and a full "insert or replace" statement? –  Jul 30 '12 at 10:13
  • 1
    `ExecuteNonQuery` returns the number of rows affected, so if your update returns 0, do an insert. – Thomas Jul 30 '12 at 10:16

4 Answers4

4

I tested Chris suggestion but the rowid still gets changed. I think the best alternative is to do a SELECT to see if a row with that key already exist. If so, UPDATE, otherwise, INSERT... good old fashion but guaranteed to work.

SHamel
  • 189
  • 1
  • 8
3

Combine it with select, like this

INSERT or REPLACE INTO test (ROWID, table_id, some_field)
VALUES ((SELECT ROWID from test WHERE table_id = 'foo' UNION SELECT max(ROWID) + 1 from test limit 1), 'foo','bar')
Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216
1

You need to specify that your table_id is unique in addition to being the primary key:

sqlite> CREATE TABLE test (
    table_id TEXT NOT NULL,
    some_field TEXT NOT NULL,
    PRIMARY KEY(table_id),
    UNIQUE(table_id)
);

sqlite> insert or replace into test values("xyz", "other");
sqlite> select * FROM test;
xyz|other
sqlite> insert or replace into test values("abc", "something");
sqlite> insert or replace into test values("xyz", "whatever");
sqlite> select * FROM test;
abc|something
xyz|whatever
Chris
  • 3,445
  • 3
  • 22
  • 28
1

From version 3.24.0 (2018-06-04), SQLite now supports an UPSERT clause that will do exactly what the OP needed: https://www.sqlite.org/lang_UPSERT.html

The insert would now look like this:

INSERT INTO test (table_id, some_field) VALUES ("foo","baz")
ON CONFLICT(table_id) DO UPDATE SET some_field=excluded.some_field;
Milan
  • 93
  • 1
  • 8