Setting query result as default column value without using triggers - sqlite

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.

Related

SQLITE get generated column type

After creating an sqlite table with a generated column in it, the type only shows up, if it was specified, and there can be cases when junk gets into the type description as well.
Example:
create table test(
id integer primary key not null,
gen generated always as (id * 2) stored
);
Using pragma table_xinfo(test); afterwards nets the following output:
0|id|INTEGER|1||1|0
1|gen||0||0|3
The type is simply missing from the correct column.
If the column were to be created with:
gen integer generated always as (id * 2) stored
instead, then the type would correctly show up as INTEGER.
Are there any methods that would get the type of a column in a table without having to resort to parsing the table creation code?
Nevermind, as usual, I find the answer right after asking it. According to sqlite documentation:
The datatype and collating sequence of the generated column are determined only by the datatype and COLLATE clause on the column definition. The datatype and collating sequence of the GENERATED ALWAYS AS expression have no affect on the datatype and collating sequence of the column itself.
Which I assume means, that just as in other places, if the datatype is not specified, it is thought of as a blob.

Sqlite INSERT INTO ... SELECT using ORDER BY

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.

SQLite: insert as Integer and as Text

Given we have a simple table like
CREATE TABLE A(
amount INTEGER
);
What is the difference between queries
INSERT INTO A VALUES(4);
and
INSERT INTO A VALUES('12');
As seen in schema, amount is an INTEGER column. The first query operates with just that - an integer, but the second one operates with a string '12'. Yet both queries work just fine, the table gets values 4 and 12, and can select or, say, sum them up correctly as two valid Integers:
SELECT sum(amount) AS "Total" FROM A;
correctly yields 16.
So is there a difference between inserting an integer as (4) and inserting it as ('12') into the INTEGER-type column?
SQLite tries to convert your String into an Integer before inserting the value into your table as described in the manual.
The type affinity of a column is the recommended type for data stored in that column. The important idea here is that the type is recommended, not required. Any column can still store any type of data. It is just that some columns, given the choice, will prefer to use one storage class over another.

Insert or ignore every column

I have a problem with a sqlite command.
I have a table with three columns: Id, user, number.
The id is continuing. Now if I put a user and a number inside my list, my app should compare if such a user with this number already exist. The problem is, if I use a standard "insert or ignore" command, the Id column is not fixed, so I will get a new entry every time.
So is it possible just two compare two of three columns if they are equal?
Or do I have to use a temporary list, where are only two columns exist?
The INSERT OR IGNORE statement ignores the new record if it would violate a UNIQUE constraint.
Such a constraint is created implicitly for the PRIMARY KEY, but you can also create one explicitly for any other columns:
CREATE TABLE MyTable (
ID integer PRIMARY KEY,
User text,
Number number,
UNIQUE (User, Number)
);
You shouldn't use insert or ignore unless you are specifying the key, which you aren't and in my opinion never should if your key is an Identity (Auto number).
Based on User and Number making a record in your table unique, you don't need the id column and your primary key should be user,number.
If for some reason you don't want to do that, and bearing in mind in that case you are saying that User,Number is not your uniqueness constraint then something like
if not exists(Select 1 From MyTable Where user = 10 and Number = 15)
Insert MyTable(user,number) Values(10,15)
would do the job. Not a SqlLite boy, so you might have to rwiddle with the syntax and wrap escape your column names.

Strange sqlite3 behavior

I'm working on a small SQLite database using the Unix command line sqlite3 command tool. My schema is:
sqlite> .schema
CREATE TABLE status (id text, date integer, status text, mode text);
Now I want to set the column 'mode' to the string "Status" for all entries. However, if I type this:
sqlite> UPDATE status SET mode="Status";
Instead of setting column 'mode' to the string "Status", it sets every entry to the value that is currently in the column 'status'. Instead, if I type the following it does the expected behavior:
sqlite> UPDATE status SET mode='Status';
Is this normal behavior?
This is also a FAQ :-
My WHERE clause expression column1="column1" does not work. It causes every row of the table to be returned, not just the rows where column1 has the value "column1".
Use single-quotes, not double-quotes, around string literals in SQL. This is what the SQL standard requires. Your WHERE clause expression should read: column1='column2'
SQL uses double-quotes around identifiers (column or table names) that contains special characters or which are keywords. So double-quotes are a way of escaping identifier names. Hence, when you say column1="column1" that is equivalent to column1=column1 which is obviously always true.
http://www.sqlite.org/faq.html#q24
Yes, that's normal in SQL.
Single quotes are used for string values; double quotes are used for identifiers (like table or column names).
(See the documentation.)

Resources