Sqlite INSERT INTO ... SELECT using ORDER BY - sqlite

I have a table as below:
CREATE TABLE IF NOT EXISTS TRACE_TABLE ([TRACE_NUM] INTEGER NOT NULL PRIMARY KEY [TRACE_ID] INTEGER NOT NULL [TRACE_TIME_DELTA] TEXT NOT NULL [TRACE_TIME_HEX] INTEGER NOT NULL [TRACE_TIME_AHB] INTEGER NOT NULL [TRACE_PARAM_TEXT] TEXT NOT NULL [TRACE_PARAM_TEXT_DECODED] TEXT);
Now I want to sort this table using a column. To do this I do following:
Create a new table TRACE_TABLE_TEMP using above statement if not exists.
Then delete all rows (in case any exists) by earlier operations
Then copy all rows from TRACE_TABLE to TRACE_TABLE_TEMP but in sorted order using a column.
I try to execute the statement in Sqlite DB browser but I am not getting the expected result. Please see below, the TRACE_NUM column is not sorted as DESC.
How do I copy the table to another in sorted order?

The documentation says:
If a SELECT statement that returns more than one row does not have an ORDER BY clause, the order in which the rows are returned is undefined.
So it does not make much sense to change the order in which rows are stored, because you'd have to put the same ORDER BY on the queries used to read the data later.
Anyway, the error is that 'TRACE_NUM' is a constant string. To refer to the contents of the column, use TRACE_NUM.

Related

Adapt ON CONFLICT clause to new unique index?

I want to add an extra unique constraint to an existing table. This and other answers say it's not possible with sqlite, and suggest creating an unique index:
ALTER TABLE example ADD COLUMN new_unique TEXT;
CREATE UNIQUE INDEX new_unique_index ON example(new_unique);
This seems to work. However, I'm having trouble with UPSERTs:
INSERT INTO example (foo, old_unique, new_unique) VALUES ('foo', 'old', 'new') ON CONFLICT(old_unique, new_unique) DO UPDATE SET foo='foo';
This gives an error:
ON CONFLICT cause does not match any PRIMARY KEY or UNIQUE constraint
Is there any way I could adapt the ON CONFLICT clause of the statement above to work with the new "constraint"?
I tried using new_unique_index, to no avail. If it's impossible, is there any alternative to creating a new table with the new unique constraint and copying the values from the old table into the new one with NULL for the new constraint column? This would be burdensome. I imagine I could create a new table with all of the former's columns, except the old uniques, plus the new unique, and link them somehow, but it sounds messy and I have no idea how to proceed.
Minimum reproducible example:
CREATE TABLE example (foo TEXT, old_unique TEXT, UNIQUE(old_unique));
ALTER TABLE example ADD COLUMN new_unique TEXT;
CREATE UNIQUE INDEX new_unique_index ON example(new_unique);
INSERT INTO example (foo, old_unique, new_unique) VALUES ('foo', 'old', 'new') ON CONFLICT(old_unique, new_unique) DO UPDATE SET foo='foo';
Is there any way I could adapt the ON CONFLICT clause of the statement above to work with the new "constraint"?
(old_unique, new_unique) is a not a possible constraint target as there is no index that combines both columns, each is an individual constraint (so you could use one or the other, as my understanding is that you are limited to a single UPSERT clause and a single conflict target).
If instead of :-
CREATE UNIQUE INDEX new_unique_index ON example(new_unique);
You used
CREATE UNIQUE INDEX new_unique_index ON example(old_unique,new_unique);
Then the following will work :-
INSERT INTO example (foo,old_unique,new_unique) VALUES('foo','old','new') ON CONFLICT (old_unique,new_unique) DO UPDATE SET foo = 'foo';
(well at least not be rejected due to no covering primary key or index for the given conflict target).
If it's impossible, is there any alternative to creating a new table with the new unique constraint and copying the values from the old table into the new one with NULL for the new constraint column? This would be burdensome.
It's not really burdensome e.g. you could use :-
CREATE TABLE IF NOT EXISTS temp_example (foo, old_unique,new_unique, UNIQUE(old_unique,new_unique));
INSERT INTO temp_example SELECT *,null FROM example;
ALTER TABLE example RENAME TO old_example;
ALTER TABLE temp_example RENAME TO example;
DROP TABLE If EXISTS old_example;
i.e. as you are adding a column and it will be the last column then there is no need to code column names.

How to handle date type in SQLite?

I've created a table, where I have "Date of birth" column of date type. The problem is that I can insert anything and it's successfully done. I want that field to restrict opportunities like inserting strings and not related stuff.
insertions
wrongResults
I've searched for the solution, but I could only find codes for getting the current time in different formats. I also don't get how exactly modifiers work (https://www.sqlite.org/lang_datefunc.html).
Bar the rowid column or an alias of the rowid column, any type of value can be stored in an type of column. That is the type of column does not restrict/constrain the data that can be stored.
p.s. there is no DATE type rather due to SQLite's flexibility DATE actually has a type (type affinity) of NUMERIC (not that that matters that much). You might find Datatypes In SQLite Version 3 an interesting read or perhaps this How flexible/restricive are SQLite column types?.
the rowid and, therefore an alias thereof, column MUST be an integer. Although typically you allow SQLite to assign the value.
You should either check the data programatically or alternately use a CHECK constraint when defining the column in the CREATE TABLE SQL.
A CHECK constraint may be attached to a column definition or specified
as a table constraint. In practice it makes no difference. Each time a
new row is inserted into the table or an existing row is updated, the
expression associated with each CHECK constraint is evaluated and cast
to a NUMERIC value in the same way as a CAST expression. If the result
is zero (integer value 0 or real value 0.0), then a constraint
violation has occurred. If the CHECK expression evaluates to NULL, or
any other non-zero value, it is not a constraint violation. The
expression of a CHECK constraint may not contain a subquery.
SQL As Understood By SQLite - CREATE TABLE
Example
Consider the following code :-
DROP TABLE IF EXISTS mychecktable ;
CREATE TABLE IF NOT EXISTS mychecktable (mycolumn BLOB CHECK(substr(mycolumn,3,1) = '-'));
INSERT INTO mychecktable VALUES('14-03-1900');
INSERT INTO mychecktable VALUES('1900-03-14'); -- ouch 3rd char not -
The is will result in :-
DROP TABLE IF EXISTS mychecktable
> OK
> Time: 0.187s
CREATE TABLE IF NOT EXISTS mychecktable (mycolumn BLOB CHECK(substr(mycolumn,3,1) = '-'))
> OK
> Time: 0.084s
INSERT INTO mychecktable VALUES('14-03-1900')
> Affected rows: 1
> Time: 0.206s
INSERT INTO mychecktable VALUES('1900-03-14')
> CHECK constraint failed: mychecktable
> Time: 0s
i.e. the first insert is successful, the second insert fails.
Usually you would enforce the correct format in your application, but you can also add constraints to your table definition to prevent this, e.g.,
CREATE TABLE users(...,
DoB TEXT CHECK(DATE(DoB) NOT NULL AND DATE(DoB)=DoB)
)

Setting query result as default column value without using triggers

I'm trying to create table with default primary key (not autoincrement), similar with oracle
fk_id varchar2(32) default sys_guid()
so table definition is
CREATE TABLE `t_table` (
`fk_id` TEXT DEFAULT 'select lower(hex(randomblob(16)))' UNIQUE,
`fv_name` TEXT,
PRIMARY KEY(`fk_id`)
);
and yes, i'm getting this select as string value while inserting.
so is there any solution without using triggers?
thank you.
Using 'select lower(hex(randomblob(16)))' is enclosing the subquery as a string/text literal and will work only once as UNIQUE has been specified (no need as making the column PRIMARY KEY implies UNIQUE) thus any subsequent inserts would fail.
Assuming that you want the DEFAULT value to be the result of the of lower(hex(randomblob(16)) then you cannot use a subquery as the value is then not considered as a CONSTANT.
For the purposes of the DEFAULT clause, an expression is considered
constant if it contains no sub-queries, column or table references,
bound parameters, or string literals enclosed in double-quotes instead
of single-quotes.SQL As Understood By SQLite - CREATE TABLE
Instead you could remove the select and just use the expression, which is then considered CONSTANT.
However, to do so, you need to adhere to
If the default value of a column is an expression in parentheses, then
the expression is evaluated once for each row inserted and the results
used in the new row. SQL As Understood By SQLite - CREATE TABLE
Thus you could use :-
CREATE TABLE IF NOT EXISTS `t_table` (
`fk_id` TEXT DEFAULT (lower(hex(randomblob(16)))) UNIQUE,
`fv_name` TEXT,
PRIMARY KEY(`fk_id`)
);
Of course should the value not be unique, which would be increasingly likely, then this would result in the row not being inserted.

SQLlite: strange "Abort due to constraint violation"

I'm trying to rename a column of a table. I have a lot of tables with the word "couleur" and I renamed "manually" to "bulle".
I've successfully renamed main_groupecouleurs to main_groupebulles. Now i'm working on main_groupe. I'm trying to rename groupe_couleurs_id to groupe_bulles_id
The SQL is quite self-explaining:
BEGIN TRANSACTION;
DROP INDEX main_groupe_fc5cee5b;
CREATE TABLE main_groupe7e12
(
id INTEGER PRIMARY KEY NOT NULL,
description TEXT NOT NULL,
exemple TEXT,
groupe_bulles_id INTEGER DEFAULT NULL,
reference TEXT,
FOREIGN KEY (groupe_bulles_id) REFERENCES main_groupebulles(id)
DEFERRABLE INITIALLY DEFERRED
);
CREATE UNIQUE INDEX main_groupe_fc5cee5b ON main_groupe7e12 (groupe_bulles_id);
INSERT INTO main_groupe7e12(id, description, exemple, groupe_bulles_id, reference)
SELECT id, description, exemple, groupe_couleurs_id, reference
FROM main_groupe;
DROP TABLE main_groupe;
ALTER TABLE main_groupe7e12 RENAME TO main_groupe;
COMMIT;
When I run it, I get:
[SQLITE_CONSTRAINT] Abort due to constraint violation
(UNIQUE constraint failed: main_groupe7e12.groupe_bulles_id)
This means (I think I'm wrong here but I dont know what I'm missing) that it tries to insert some groupe_couleurs_id that are not in the referring table (= main_groupebulles). Thus I tried to see in the original table the problem:
SELECT * FROM main_groupe WHERE groupe_couleurs_id NOT IN (
SELECT id FROM main_groupebulles
);
I got no rows! What am I missing?
You have an UNIQUE index on your groupe_bulles_id column but based on the comments, there are a lot of valid duplicate values for that column coming from main_groupe.groupe_couleus_id and that causes the constraint violation.
Since having duplicate values is what you want, remove the UNIQUE from the CREATE UNIQUE INDEX ....

Sort an entire SQLite table

I have an SQLite table that I need to sort. I am familiar with the ORDER BY command but this is not what I am trying to accomplish. I need the entire table sorted within the database.
Explanation:
My table uses a column called rowed which sets the order of the table (a key?). I need to sort the table by another column called name and then re-assign rowid numbers in alphabetical order according to name. Can this be done?
Assuming you created your original table like so:
CREATE TABLE my_table (rowid INTEGER PRIMARY KEY, name TEXT, somedata TEXT) ;
You can create another sorted table like so:
CREATE TABLE my_ordered_table (rowid INTEGER PRIMARY KEY, name TEXT, somedata TEXT) ;
INSERT INTO my_ordered_table (name, somedata) SELECT name,somedata FROM my_table
ORDER BY name ;
And if you then want to replace the original table:
DROP TABLE my_table ;
ALTER TABLE my_ordered_table RENAME TO my_table;
I think this issue relates to wanting the primary key to mean something. Avoid that trap. Choose an arbitrarily generated primary key that uniquely identifies a row of data and has no other meaning. Otherwise you will eventually run into the problem of wanting to alter the primary key values to preserve the meaning.
For a good explanation of why you should rely on ORDER BY to retrieve the data in the desired order instead of assuming the data will otherwise appear in a sequence determined by the primary key see Cruachan's answer to a similar question

Resources