0

I'm using SQLite to store an id, uuid, value and a caught value.

I create the table with this command:

CREATE TABLE IF NOT EXISTS statz_fish_caught 
('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
 'uuid' TEXT NOT NULL,
 'value' INTEGER NOT NULL,
 'caught' TEXT NOT NULL);

I use this command to insert (or replace) rows:

INSERT OR REPLACE INTO statz_fish_caught (uuid,value,caught) 
VALUES ('uuid comes here', a number here, 'a certain string').

Let's say you have this data in the table:

http://pasteboard.co/gofap3y.png

This data would imply that UUID1 caught a total of 9 (1+5+3) fishes. 1 of fish type 1, 5 of fish type 2 and 3 of fish type 3. UUID2 has only caught 10 fishes of fish type 1. Now let's imagine UUID1 catches a new fish type: fish type 4. The database should create a new row with an auto incremented value of id 5, with uuid as 'uuid1', value=1 and caught=fish type 4.

Now let's also imagine UUID catches another fish of fish type 3. The row of uuid1 with fish type 3 (it has id 3) should be updated to represent value 4, like this:

http://pasteboard.co/goBZatx.png

Is this possible, if yes, how?

Staartvin
  • 11
  • 1
  • 5

2 Answers2

1

You are using an INTEGER AUTOINCREMENT PRIMARY KEY, and you don't have any other UNIQUE field in your table: this means that it is impossible to have a conflict between the existing rows and the one you are trying to add, therefore there will be no REPLACE

You should change the definition of your table like this:

CREATE TABLE IF NOT EXISTS statz_fish_caught 
('id' INTEGER PRIMARY KEY NOT NULL,
 'uuid' TEXT NOT NULL,
 'value' INTEGER NOT NULL,
 'caught' TEXT NOT NULL);

Be aware that, by changing this, you have to manually put the id value when you add the rows, since it's not managed by the DBMS anymore.

Edit: Here you can find a working example; notice how the value of the primary key hasn't changed.

Edit #2: As suggested by ishmaelMakitla, putting UNIQUE for the UUID field should do the trick; I've updated my answer accordingly.

CREATE TABLE IF NOT EXISTS statz_fish_caught 
('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
 'uuid' TEXT NOT NULL UNIQUE,
 'value' INTEGER NOT NULL,
 'caught' TEXT NOT NULL);

A warning: as stated in the SQLite documentation,

The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.

Plus, as you can see in this example, the id of the updated row has changed, which is something that I strongly recommand to avoid.

Edit #3 It took me a while, but this example should do what you want.

The query you have to use is something like this (6 is the caught fishes you want to add):

INSERT OR REPLACE INTO statz_fish_caught (uuid,value,caught) 
VALUES (
     -- (select `id` from statz_fish_caught where uuid = 'uu1'),
     'uu1', 
     (select `value` from statz_fish_caught where uuid = 'uu1') + 6, 
     (select `caught` from  statz_fish_caught where uuid = 'uu1')
);

Note that if you want to keep the current value of the id field for the updating row, you have to uncomment the first line of the values and add the id field in the list of columns of the statement.

Cynical
  • 9,328
  • 1
  • 15
  • 30
  • This is indeed what I need. Is there a way to have the DBMS automatically do the id column? If not, how would I go about manually updating the id every time? I would first need to know what the id is, right? – Staartvin Apr 17 '16 at 20:22
  • To get rid of the autoincrement you should check with whoever uses this database if there is another field that can be used as primary key. If for some reason you are stuck with the autoincrement (which is theoretically not the best approach), you can set another field as `UNIQUE`, like suggested in the other answer. This way, the `Replace` takes effect when that field has a conflict. – Cynical Apr 17 '16 at 20:54
  • It seems I'm too vague. I've updated my original post with different pictures explaining what each column meant. Is there a way to get that working with SQLite? (btw, you're second solution was not what I was looking for, sorry!) – Staartvin Apr 17 '16 at 22:17
  • Can a UUID catch, in the same statement, more than one fish of a certain type? Imean, Can it be the case where you must add more than one fish? – Cynical Apr 18 '16 at 09:28
  • Yes, a UUID can catch an arbitrary amount of fish for a certain type at once. – Staartvin Apr 18 '16 at 15:24
0

In addition to what Cynical said, you should set UUID to UNIQUE - this way, the row with a matching UUID will be replaced. So the table should be modified as follows:

CREATE TABLE `statz_fish_caught` (
`id`    INTEGER NOT NULL,
`uuid`  TEXT NOT NULL UNIQUE,
`value` INTEGER NOT NULL,
`caught`    TEXT NOT NULL,
PRIMARY KEY(id)
);

I have tested this by doing the following:

INSERT OR REPLACE INTO statz_fish_caught 
(uuid,value,caught) VALUES (hex(randomblob(16)), 1, 'caught-1 ');

Then I executed the following query string (note, I used the UUID generated by hex(randomblob(16) in the previous query). So by running :

INSERT OR REPLACE INTO statz_fish_caught (uuid,value,caught) VALUES ('uuid-of-row-to-update', 2, 'caught-1-updated'); 
ishmaelMakitla
  • 3,784
  • 3
  • 26
  • 32
  • I think I was not clear enough. The _caught_ column can have multiple values, but should group if it is the same. It should work like [this](http://sqlfiddle.com/#!5/eecd2/1), but **with** the automatic handling of the _id_ column. Is that possible. – Staartvin Apr 17 '16 at 20:21
  • In my answer, I assumed that the UUID will be the same for a replace. Now with your clarification, then the "caught" column must have the UNIQUE constraint on it - otherwise there is no way of knowing which row the query should replace. As a result, a new row gets inserted. The reason why it works when you specify the same id value (1) in the fiddle, is because the ID has the unique constraint automatically by being a primary key. Accordingly, you should modify your table, making the "caught" column unique: `caught TEXT NOT NULL UNIQUE,` – ishmaelMakitla Apr 17 '16 at 21:30
  • This didn't do the trick. See my original post, I edited it and clarified what I specifically want my database to do. – Staartvin Apr 17 '16 at 22:18
  • @Staartvin, it seems therefore that you need to **match** the **UUID** and the **caught** (type of fish caught). So basically, you create a unique constraint on the two columns (uuid and caught). That's the only way I think this can work as you expect it. To do this, you put the UNIQUE declaration within the column definition section of the query when creating the table. See the voted answer on Setting Unique Constraint on Multiple Columns: http://stackoverflow.com/questions/2701877/sqlite-table-constraint-unique-on-multiple-columns. I hope this helps. – ishmaelMakitla Apr 18 '16 at 10:35