Update statement for a list of strings - sqlite

I'm using sqlite3 and my table has a text field that actually has a list of strings.
So a sample select (select * from table where id=1) would return for example
1|foo#bar.com|21-03-2015|["foo", "bar", "foobar"]
I couldn't figure out how the sqlite statement for updating the list is though. I tried
update table set list="["foo", "bar"] where id=1;
update table set list=["foo", "bar"] where id=1;
update table set list="\["foo", "bar"\]" where id=1;
update table set list=(value) where id=1 VALUES (["foo", "bar"])

This is the statement you need:
UPDATE table SET list = '[\"foo\", \"bar\"]' WHERE id = 1

Related

SQLite: updating column from another table

I have a old table and a new table. what i need is to copy the uuId of the old table to the new Table.
im following some answers from other references but i can`t get the ideal answer.
the closest answer i found is this:
update table1
set table1.uuid =
(select table2.uuid from table2 where table1.itemDescription = table2.itemDescription)
when i execute this query, it only saves the 1st found uuid of the old table to all the entry in the new Table.
Sample Table2 (old table):
uuid|itemDescription
1|item1
2|item2
3|item3
Sample Table1 (new Table):
uuid|itemDescription
Null|item1
Null|item2
Null|item3
Desired Output:
uuid|itemDescription
1|item1
2|item2
3|item3
what happens:
uuid|itemDescription
1|item1
1|item2
1|item3
In SQLite, you must not use the table name in the SET clause:
update table1
set uuid =
(select table2.uuid from table2 where table1.itemDescription = table2.itemDescription);
Try like this :
UPDATE table1
SET table1.uuid = table2.uuid
FROM table2 WHERE table1.itemDescription = table2.itemDescription
No need for subquery, otherwise you need to link item description in outer query also

SQLite trigger after update

My table has timestamp column. I want a trigger which sets timestamp to 0 on affected rows when a row is updated and the timestamp is not specified in the update statement.
If I use this trigger:
CREATE TRIGGER AFTER UPDATE ON mytable FOR EACH ROW
WHEN (NEW.timestamp IS NULL)
BEGIN
UPDATE mytable SET timestamp = 0 WHERE id = NEW.id;
END;
then the trigger doesn't fire for this update statement:
UPDATE mytable SET comecolumn='some'
I.e. timestamp of affected rows doesn't change to 0.
Can you please help me define the trigger?
The only way to make additional changes to a row in an UPDATE trigger is to execute another UPDATE on the same table afterwards.
The only way to detect whether a column value is changed is to compare the old and the new row values; the trigger does not know which columns actually were mentioned in the original UPDATE statement.
To prevent the trigger from triggering itself recursively, you should restrict it to be triggered by changes of all columns except the timestamp:
CREATE TRIGGER clear_timestamp
AFTER UPDATE OF all_the, other, columns ON MyTable
FOR EACH ROW
WHEN OLD.timestamp = NEW.timestamp
BEGIN
UPDATE MyTable
SET timestamp = 0
WHERE id = NEW.id;
END;
I think the problem is that in the SET statement is expanded to every column, with every column set to the current value in the database. So the original only trigger works, if the current timestamp column is NULL.
A solution could be to create another trigger that resets the timestamp column to NULL before an UPDATE.
CREATE TRIGGER "set_null"
BEFORE UPDATE ON "mytable" FOR EACH ROW
BEGIN
UPDATE mytable set timestamp = NULL where rowid = NEW.rowid;
END
This way the NEW.timestamp is NULL if it is not specified in the UPDATE SET.
Obviously now a NOT NULL constraint cannot be set on timestamp.
Another problem is that trigger recursion must be off when executing a update query:
PRAGMA recursive_triggers = OFF;
Here is another way:
import sqlite3
conn = sqlite3.connect(':memory:')
c = conn.cursor()
name = {'name':'jack'}
c.execute("""CREATE TABLE Programs (
id INTEGER PRIMARY KEY,
name VARCHAR(64) NOT NULL,
time_added INTEGER
);""")
c.execute("""CREATE TRIGGER program_time_added AFTER INSERT ON Programs
FOR EACH ROW
BEGIN
UPDATE Programs SET time_added =datetime('now', 'localtime') WHERE id = NEW.id;
END;""")
c.execute('INSERT INTO Programs (name) VALUES (?)', [name['name']])

update and insert triggers in sqlite

I want to have riggers that set the last_modified column automatically each time a row in updated or inserted.
Lets say I have an ID that is unique to each row.
This is my query:
CREATE TRIGGER insert_trigger
AFTER INSERT ON TABLE_NAME
BEGIN
update TABLE_NAME set last_modified =strftime('%Y-%m-%d %H:%M:%S:%s','now', 'localtime') where id = old.id;
END;
After creating this trigger, when I try to insert I get the error:
no such column: old.id
I can understand why I get this error, but how can I create a proper trigger?
When inserting, there is no old row.
To get the ID of the new row, use NEW.id.

SQLite update trigger changes all rows in the table

Problem: a simplest possible update trigger writes a new value to all table rows instead of just the row being updated. Here is the table:
[names]
id INTEGER PRIMARY KEY
name TEXT
len INTEGER
Now I want to create triggers to update 'len' with the length of 'name'. This INSERT trigger seems to be doing the job corectly:
CREATE TRIGGER 'namelen' AFTER INSERT ON 'names'
BEGIN
UPDATE 'names' SET len = length(NEW.name) WHERE (id=NEW.id);
END;
Problems begin when I add a similar UPDATE trigger:
CREATE TRIGGER 'namelenupd' AFTER UPDATE ON 'names'
BEGIN
UPDATE 'names' SET len = length(NEW.name) WHERE (OLD.id=NEW.id);
END;
The update trigger writes the new length to all rows of the table, despite the WHERE clause. For example, if I say
UPDATE 'names' SET name='foo' where id=1;
then the value of 'len' becomes 3 for all rows of the table. I've looked at sqlite trigger examples and I can't see my error. What else must I do to make sure the trigger updates the 'len' column only in the row(s) that are actually updated?
Both OLD.xxx and NEW.xxx refer to the table row that caused the trigger to run.
The UPDATE statement inside the trigger runs independently; if you want to restrict it to one table row, you have to explicitly do this in its WHERE clause by filtering on that statement's table values, i.e., names.id or just id.
When the original UPDATE statement does not change the id column, the old and new id values are the same, and the expression OLD.id=NEW.id is true for all records in the table, as seen by the inner UPDATE statement.
The correct trigger looks like this:
CREATE TRIGGER "namelenupd"
AFTER UPDATE OF name ON "names"
BEGIN
UPDATE "names" SET len = length(NEW.name) WHERE id = NEW.id;
END;
Had the same issue, here's the syntax from my trigger
You would change "ALTER" to "CREATE" depending on what you already have (or not)
You have "id" as your primary key
Your dbo is "names"
Obviously, this will set the name value to "foo" (not really what you wanted). The key seems to be the last line, where you set inner join inserted on names.Id = inserted.Id.
USE [yourDBname]
ALTER TRIGGER [dbo].[yourTrigger]
ON [dbo].[names]
After INSERT, UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Select id from inserted
begin
update [dbo].names
set [dbo].names.name = 'foo'
from dbo.names
inner join inserted
on names.id = inserted.id
END

SQLITE fill value with unique random table

I want to create a table with a field that is unique and limited to a certain value. Lets say that the limit is 100, the table is full, I remove a random row, and when I create a new row it has the value that was freed before.
It doesn't need to be the fastest thing in the world (the limit is quite small), I just want to implement it in a DB.
Any ideas?
Create one more column in main table, say deleted (integer, 0 or 1). When you need to delete with certain id, do not really delete it, but simply update deleted to 1:
UPDATE mytable SET deleted=1 WHERE id = <id_to_delete>
When you need to insert, find id to be reused:
SELECT id FROM mytable WHERE deleted LIMIT 1
If this query returns empty result, then use INSERT to create new id. Otherwise, simply update your row:
UPDATE mytable SET deleted=0, name='blah', ... WHERE id=<id_to_reuse>
All queries reading from your main table should have WHERE constraint with NOT deleted condition:
SELECT * FROM mytable WHERE NOT deleted
If you add index on deleted, this method should work fast even for large number of rows.
This solution does everything in a trigger, so you can just use a normal INSERT.
For the table itself, we use an autoincrementing ID column:
CREATE TABLE MyTable(ID INTEGER PRIMARY KEY, Name);
We need another table to store an ID temporarily:
CREATE TABLE moriturus(ID INTEGER PRIMARY KEY);
And the trigger:
CREATE TRIGGER MyTable_DeleteAndReorder
AFTER INSERT ON MyTable
FOR EACH ROW
WHEN (SELECT COUNT(*) FROM MyTable) > 100
BEGIN
-- first, select a random record to be deleted, and save its ID
DELETE FROM moriturus;
INSERT INTO moriturus
SELECT ID FROM MyTable
WHERE ID <> NEW.ID
ORDER BY random()
LIMIT 1;
-- then actually delete it
DELETE FROM MyTable
WHERE ID = (SELECT ID
FROM moriturus);
-- then change the just inserted record to have that ID
UPDATE MyTable
SET ID = (SELECT ID
FROM moriturus)
WHERE ID = NEW.ID;
END;

Resources