Row deleted when it shouldn't be - sqlite

If I execute the following script in sqlite 3.8.8.3
PRAGMA foreign_keys=on;
create table A (
k integer primary key not null
);
create table B (
value text primary key,
k integer references A(k) on delete cascade
);
create table C (
k integer primary key,
value text
);
create trigger C_A before insert on C
begin
insert or ignore into A values(NEW.k);
end;
insert into A values (5);
select * from A;
insert into B values ('asdf', 5);
select * from B;
insert or ignore into A values(5); --just calling this works right
select * from B;
insert or ignore into C values (5, 'qwer'); --this works too
select * from B;
insert or replace into C values (5, 'qwer'); --this doesn't work
select * from B; --doesn't print anything
I get the output
5
asdf|5
asdf|5
asdf|5
when I'm expecting the output
5
asdf|5
asdf|5
asdf|5
asdf|5
It seems like the "or replace" gets propagated into the trigger, replacing the row in A, and deleting the row in B.
Is this expected behavior? Am I misunderstanding what this should do?

This is documented:
An ON CONFLICT clause may be specified as part of an UPDATE or INSERT action within the body of the trigger. However if an ON CONFLICT clause is specified as part of the statement causing the trigger to fire, then conflict handling policy of the outer statement is used instead.

Related

SQLite UNION right only if left is empty

In SQLite there is no such function to UNION only if left expression results empty set.
Consider these as two base tables test and test2:
create table test(
id integer not null primary key,
val integer not null
);
insert into test values(1, 10);
insert into test values(2, 20);
insert into test values(3, 30);
create table test2(
id integer not null primary key,
val integer not null
);
insert into test2 values(1, 100);
insert into test2 values(2, 200);
insert into test2 values(3, 300);
I have this simple query:
select * from test
union
select * from test2;
I want this to always query the first select and the second if (and only if) the first gives empty result.
To illustrate:
select * from test
union
select * from test2;
This shall return all rows from test, and then quit: don't touch test2 at all.
Another sample:
select * from test where val > 50
union
select * from test2;
First query gives empty results, move on and do the second select, shall result all rows from test2.
I want this to be as fast as possible => therefore I don't want to add a subquery for the second select.
Here is the playground.
A SQL SELECT is declarative. It expresses what you want, not how to obtain it. It is up to the db engine to convert it to a query plan. Some SQL dialects allow to hint the engine to do things a certain way, but not SQLite.
The only solution is to query the two part from an imperative language (python, java, C#, ...) that allows you to implements the do something first and check result then do something else
I don't want to add a subquery for the second select.
Well, the two queries are functionally independent in the query, and there is no way for the second query to tell that the first one came up empty, unless you use a subquery.
So, you would typically use a not exists condition in the second query, with a subquery that matches the first query.
So:
select * from test
union all
select * from test2 where not exists (select 1 from test)
Or if there is a where clause in the first query:
select * from test where val > 50
union all
select * from test2 where not exists (select 1 from test where val > 50)

Integer dividing columns - SQLite

How is it possible to divide 2 columns and update with the result a third one?
UPDATE Table
SET success = (number_won_games / number_all_games)*100
WHERE name_game = 'some name'
This code is not updating my column, so I thought somebody of you guys could help me?
I believe your issue may be that number_won_games and number_all_games are integers and thus that the division will always be be 0 and thus 0 multiplied by 100 will then be 0, perhaps giving the impression that nothing is updated.
You could try casting number_won_games and number_all_games to REAL e.g. using :-
UPDATE Table
SET success = (CAST(number_won_games AS REAL) / CAST(number_all_games AS REAL)) * 100
WHERE name_game = 'some name';
Explanatory Example
Considering the following :-
DROP TABLE IF EXISTS t;
CREATE TABLE IF NOT EXISTS t (name_game TEXT, number_won_games INTEGER, number_all_games INTEGER, success REAL);
INSERT INTO t VALUES
('game1',10,20,0.12345678);
UPDATE t SET success = (number_won_games / number_all_games) * 100;
SELECT * FROM t;
UPDATE t SET success = (CAST(number_won_games AS REAL) / CAST(number_all_games AS REAL)) * 100;
SELECT * FROM t;
WHERE clause not needed, so has not been included.
Which inserts a row with 20 games played with 10 won (thus 50 as the success rate) and with success set to a non-zero value (to show that the first update does update) then
The first UPDATE as per your example result in :-
Whilst the second UPDATE, which casts the values to REAL results in :-
I feel like a trigger is your best bet here. I don't have access to a database at the moment, but something like this would probably work.
CREATE TABLE counter(id INTEGER PRIMARY KEY AUTOINCREMENT, success REAL, number_won_games REAL, number_all_games REAL);
CREATE TRIGGER counter_update_success AFTER UPDATE ON counter
BEGIN
UPDATE counter set NEW.success=((NEW.number_won_games/NEW.number_all_games)*100.0);
END;
CREATE TRIGGER counter_create_success AFTER INSERT ON counter
BEGIN
UPDATE counter set NEW.success=((NEW.number_won_games/NEW.number_all_games)*100.0);
END;

% Wildcard not working with numbers?

I have the following sqlite db:
BEGIN TRANSACTION;
CREATE TABLE `table1` (
`Field1` TEXT
);
INSERT INTO `table1` VALUES ('testing');
INSERT INTO `table1` VALUES ('123');
INSERT INTO `table1` VALUES ('87654');
COMMIT;
This select returns the correct result:
select * from table1 where Field1 like '%e%';
However this one returns nothing?
select * from table1 where Field1 like '%2%';
Even Stranger in DB Browser for SQLite:
select * from table1 where CAST(Field1 AS Text) LIKE '%2%'
Returns:
1 Rows returned from: select * from table1 where CAST(Field1 AS Text) LIKE '2%' (took %3ms)
Maybe a bug? Drops the first %
A bug in DB browser. I raised an issue and its now been fixed in the nightlies.

Will AutoIncrement work with Check constraints?

The question is simple:
In SQLite, if I choose to AutoIncrement a primary key of type NUMERIC which has a check constraint like CHECK(LENGTH(ID) == 10), will it work correctly inserting the first value as 0000000001 and so on?
No, that does not work. Adding a check does not magically also add a way of fullfilling the check to insert the data.
See this SQLFiddle.
If you want to restrict the value of an autoincrement column like that, you need to seed the internal sequence table. (There are other ways.)
create table foo (
foo_id integer primary key autoincrement,
other_columns char(1) default 'x',
check (length(foo_id) = 10 )
);
insert into sqlite_sequence values ('foo', 999999999);
Application code is allowed to modify the sqlite_sequence table, to
add new rows, to delete rows, or to modify existing rows.
Source
insert into foo (other_columns) values ('a');
select * from foo;
1000000000|a
Trying to insert 11 digits makes the CHECK constraint fail.
insert into foo values (12345678901, 'a');
Error: CHECK constraint failed: foo
One alternative is to insert a "fake" row with the first valid id number immediately after creating the table. Then delete it.
create table foo(...);
insert into foo values (1000000000, 'a');
delete from foo;
Now you can insert normally.
insert into foo (other_columns) values ('b');
select * from foo;
1000000001|b
In fact the ID's length is 1, so it doesn't work.

counting rows of sqlite INSERT SELECT

I have two sqlite tables, where one table has a foreign key of the other.
CREATE TABLE a (id INTEGER PRIMARY KEY NOT NULL, value TEXT UNIQUE NOT NULL);
CREATE TABLE b (id INTEGER PRIMARY KEY NOT NULL, a INTEGER REFERENCES a (id) NOT NULL, value TEXT NOT NULL);
I am doing an INSERT with a SELECT into b.
INSERT INTO b (a, value) SELECT ?value, a.id FROM a WHERE a.value == ?a;
How do I know weather a row was inserted into b or not? Doing a SELECT for the just inserted values and checking weather they exist, seems rather inefficient.
I hope the changes() function can help you.
The changes() function returns the number of database rows that were
changed or inserted or deleted by the most recently completed INSERT,
DELETE, or UPDATE statement, exclusive of statements in lower-level
triggers. The changes() SQL function is a wrapper around the
sqlite3_changes() C/C++ function and hence follows the same rules for
counting changes.
So changes() returns 1 if a row was inserted and 0 otherwise.

Resources