SQLite Studio - Export database with adding quote to string number - sqlite

I cannot export my database to a sql file with adding quote to string number. I store code postal number as CHAR[5] but it exports without 'quote'.
eg: What I want my quoting string number '01234' like:
CREATE TABLE codepostal ( code CHAR( 5 ) PRIMARY KEY NOT NULL UNIQUE, name VARCHAR( 70 ) NOT NULL );
INSERT INTO [codepostal] ([code], [name]) VALUES ('01234', 'My_city');
But not 01234 (no quoting):
CREATE TABLE codepostal ( code CHAR( 5 ) PRIMARY KEY NOT NULL UNIQUE, name VARCHAR( 70 ) NOT NULL );
INSERT INTO [codepostal] ([code], [name]) VALUES (01234, 'My_city');
I want to export my db to a sql file then read it to re-create my db somewhere. But since I store code postal "01234" like CHAR[5] and it export without quoting, when I re-create my db > I losts my "0" because it read "01234" but only insert "1234" because my "01234" was no-quoting.
My SQLiteStudio was v2.1.5 and I stored as VARCHAR and TEXT but still no quoting.
Any suggestion can help, thanks. ^_^

SQLiteStudio 2.x.x is obsolete. Use the recent one (at the moment it's 3.0.6, available at its homepage). It will deal with your export correctly.

Related

Create index on timestamp delivered by JSON - incorrect datetime value

I constantly retrieve JSON data from some API and put that data into a MariaDB table.
The JSON ships with a timestamp which I'd like to place an index on, because this attribute is used for querying the table.
The JSON looks something like this (stripped):
{
"time": "2021-12-26T14:00:00.007294Z",
"some_measure": "0.10031"
}
I create a table:
CREATE TABLE some_table (
my_json JSON NOT NULL,
time TIMESTAMP AS (JSON_VALUE(my_json , '$.time')),
some_measure DOUBLE AS (JSON_VALUE(my_json , '$.some_measure'))
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;
my_json holds the entire JSON snippet, time and some_measure are virtual columns properly extracting the corresponding JSON values on the fly.
Now, trying to add an index on the TIMESTAMP attribute:
CREATE INDEX some_index ON some_table (time);
This fails:
SQL Error [1292] [22007]: (conn=454) Incorrect datetime value:
'2021-12-26T14:00:00.007294Z' for column `some_db`.`some_table`.`time` at row 1
How can I add an index on that timestamp?
The issue here is that converting a string (the JSON timestamp) to a TIMESTAMP is non-deterministic because it involves server side settings (sql_mode) and timezone settings.
Indexing virtual columns which are non-deterministic is not supported.
You would want to use a VARCHAR data type instead and index that:
CREATE TABLE some_table (
my_json JSON NOT NULL,
time VARCHAR(100) AS (JSON_VALUE(my_json , '$.time')),
some_measure DOUBLE AS (JSON_VALUE(my_json , '$.some_measure'))
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;
You should be able to create your index:
CREATE INDEX some_index ON some_table (`time`);
You can still query time because MariaDB automatically converts DATETIMEs if used against a VARCHAR:
SELECT
*
FROM some_table
WHERE time > '2008-12-31 23:59:59' + INTERVAL 1 SECOND;
The query will use the index:
I finally came up with a solution that works for me.
Changes are:
use STR_TO_DATE() to create a valid DATETIME from the JSON timestamp
make the generated (virtual) column PERSISTENT
use data type DATETIME instead of TIMESTAMP
So the new code looks like this:
CREATE TABLE some_table (
my_json JSON NOT NULL,
time DATETIME AS (STR_TO_DATE((JSON_VALUE(my_json , '$.time')), '%Y-%m-%d%#%T%.%#%#')) PERSISTENT,
some_measure DOUBLE AS (JSON_VALUE(my_json , '$.some_measure'))
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;
CREATE INDEX some_index ON some_table (`time`);

tcl var substitution in sqlite3 eval

I have a file filled with sqlite statements I'd like to parse. I've done so previously using the C-interface but now I have trouble with the Tcl interface.
sqlite3 cspdb ":memory:"
set s [read [set f [open csp_sql.txt]]]
set ms [string map {"\n" "\0"} $s]
puts $ms
cspdb eval {$ms}
The error I get is:
"near "$ms": syntax error while executing cspdb eval {$ms}"
It works fine when I paste the output from puts $ms directly into the eval brackets. I also tried "{$ms}" and just plain $ms but the result is the same; syntax error.
I might chose another solution for the problem all together but it really bugs my why it does not work...
Here is what the file looks like:
BEGIN TRANSACTION;
CREATE TABLE Symbol (
Label TEXT PRIMARY KEY,
Type TEXT DEFAULT('no_type')
);
CREATE TABLE Process (
Name INTEGER PRIMARY KEY,
Type TEXT DEFAULT('no_type')
);
CREATE TABLE Named_Process (
Label TEXT UNIQUE,
Definition INTEGER UNIQUE,
FOREIGN KEY(Label) REFERENCES Symbol (Label),
FOREIGN KEY(Definition) REFERENCES Definition(Name)
);
CREATE TABLE Definition (
Name INTEGER UNIQUE,
Definition INTEGER,
FOREIGN KEY(Name) REFERENCES Process(Name),
FOREIGN KEY(Definition) REFERENCES Process(Name)
);
CREATE TABLE Reference (
Name INTEGER UNIQUE,
Reference TEXT,
FOREIGN KEY(Name) REFERENCES Process(Name),
FOREIGN KEY(Reference) REFERENCES Definition(Name)
);
CREATE TABLE Event (
Label TEXT PRIMARY KEY,
Type TEXT DEFAULT('no_type')
);
CREATE TABLE Environment (
Label TEXT UNIQUE,
FOREIGN KEY (Label) REFERENCES Event (Label)
);
CREATE TABLE Prefix (
Name INTEGER UNIQUE,
P INTEGER,
Event TEXT,
FOREIGN KEY (Name) REFERENCES Process (Name),
FOREIGN KEY (P) REFERENCES Process (Name),
FOREIGN KEY (Event) REFERENCES Event (Label)
);
CREATE TABLE Choice (
Name INTEGER UNIQUE,
P INTEGER,
Q INTEGER,
FOREIGN KEY(Name) REFERENCES Process(Name),
FOREIGN KEY(P) REFERENCES Process(Name),
FOREIGN KEY(Q) REFERENCES Process(Name)
);
/* Language defined processes */
/* SKIP */
INSERT INTO Symbol(Label,Type) VALUES('SKIP','named_process');
INSERT INTO Named_Process(Label) VALUES('SKIP');
INSERT INTO Process(type) VALUES('definition');
UPDATE Named_Process SET Definition=last_insert_rowid() WHERE Label='SKIP';
INSERT INTO Definition(Name,Definition) VALUES(last_insert_rowid(),last_insert_rowid());
END TRANSACTION;
(Not so sure removing newlines is necessary...)
If the string that you've read from the file is SQL, you should be able to do this:
sqlite3 cspdb ":memory:"
set f [open "csp_sql.txt"]
set sql [read $f]
close $f
cspdb eval $sql
By comparison, the literal string $ms is not a valid SQL statement or query, nor is it syntactically legal to surround a SQL statement with braces (which is what "{$ms}" ended up doing; the outer "…" makes the inside just a bunch of characters).
I don't know why you are translating newlines into NULs, but that's really unlikely to be a good idea. Bulk import of data (possibly with NULs in it) should be done in a different way.
The eval subcommand created by Sqlite does limited variable substitution, but only in places where a string value is expected.
Try
cspdb eval $ms
to let the Tcl interpreter substitute the SQL statements before sending them to eval.
turns out the newline-to-null was the culprit making substitution fail. final working code:
sqlite3 cspdb ":memory:"
cspdb eval [read [set f [open csp_sql.txt]]]
the reason newline-to-null turned up at all was when trying to debug making the string match my original working C-code which used multiline string literals in which newlines diappeared. Except, "\0" is not a "disappearing" character...

SQLite UUID as column default

I am trying to reproduce the SQL Server default NEWID() value for a UNIQUEIDENTIFIER column in SQLite. It produces a UUID as a default for the column.
How can I do that in SQLite?
I found this page (Is there UID datatype in SQLITE if Yes then how to generate value for that) where they use a select statement but it is no good for DEFAULT.
NOTE : I am using the SQLite version implemented for browsers as I am using it through ionic and the cordova-sqlite plugin. So this does not contain all the features provided by SQLite and more importantly this does not contain the RANDOM function.
Yes, you can use create function to add a UUID function. By default you'd have to write it in C, but many SQLite drivers have a way to add functions in their native language. Here's an example in Perl using DBD::SQLite.
use strict;
use warnings;
use v5.10;
use DBI;
use Data::UUID;
# Connect to the database.
my $dbh = DBI->connect("dbi:SQLite:dbname=test.db", "", "", { RaiseError => 1});
# Create uuid() which calls Perl to generate a uuid.
$dbh->sqlite_create_function("uuid", 0, sub { Data::UUID->new->create_str });
# Create a table using uuid() as the default.
$dbh->do(q[drop table if exists foo]);
$dbh->do(q[
create table foo (
id int primary key default (uuid()),
name text
)
]);
# Insert some rows using the default id.
$dbh->do(q[
insert into foo (name) values ("you"), ("me")
]);
# Print out the rows.
my $rows = $dbh->selectall_arrayref(q[select * from foo]);
for my $row (#$rows) {
say "$row->[0], $row->[1]";
}
And the result is.
E9768488-834F-11E6-AA60-F143DC5749B0, you
E976B69C-834F-11E6-AA60-F143DC5749B0, me

Strange SQLite behavior: Not returning results on simple queries

Ok, so I have a basic table called "ledger", it contains fields of various types, integers, varchar, etc.
In my program, I used to use a query with no "from" predicate to collect all of the rows, which of course works fine. But... I changed my code to allow selecting one row at a time using "where acctno = x" (where X is the account number I want to select at the time).
I thought this must be a bug in the client library for my programming language, so I tested it in the SQLite command-line client - and it still doesn't work!
I am relatively new to SQLite, but I have been using Oracle, MS SQL Server, etc. for years and never seen this type of issue before.
Other things I can tell you:
* Queries using other integer fields also don't work
* Queries on char fields work
* Querying it as a string (with the account number on quotes) still doesn't work. (I thought maybe the numbers were stored as a string inadvertently).
* Accessing rows by rowid works fine - which is why I can edit the database with GUI tools with no noticeable problem.
Examples:
Query with no WHERE (works fine):
1|0|0|JPY|8|Paid-In Capital|C|X|0|X|0|0||||0|0|0|
0|0|0|JPY|11|Root Account|P|X|0|X|0|0|SYSTEM|20121209|150000|0|0|0|
3|0|0|JPY|13|Mitsubishi Bank Futsuu|A|X|0|X|0|0|SYSTEM|20121209|150000|0|0|0|
4|0|0|JPY|14|Japan Post Bank|A|X|0|X|0|0|SYSTEM|20121209|150000|0|0|0|
...
Query with WHERE clause: (no results)
sqlite> select * from ledger where acctno=1;
sqlite>
putting quotes around the 1 above changes nothing.
Interestingly enough, "select * from ledger where acctno > 1" returns results! However since it returns ALL results, it's not terrible useful.
I'm sure someone will ask about the table structure, so here goes:
sqlite> .schema ledger
CREATE TABLE "LEDGER" (
"ACCTNO" integer(10,0) NOT NULL,
"drbal" integer(20,0) NOT NULL,
"crbal" integer(20,0) NOT NULL,
"CURRKEY" char(3,0) NOT NULL,
"TEXTKEY" integer(10,0),
"TEXT" VARCHAR(64,0),
"ACCTYPECD" CHAR(1,0) NOT NULL,
"ACCSTCD" CHAR(1,0),
"PACCTNO" number(10,0) NOT NULL,
"CATCD" number(10,0),
"TRANSNO" number(10,0) NOT NULL,
"extrefno" number(10,0),
"UPDATEUSER" VARCHAR(32,0),
"UPDATEDATE" text(8,0),
"UPDATETIME" TEXT(6,0),
"PAYEECD" number(10,0) NOT NULL,
"drbal2" number(10,0) NOT NULL,
"crbal2" number(10,0) NOT NULL,
"delind" boolean,
PRIMARY KEY("ACCTNO"),
CONSTRAINT "fk_curr" FOREIGN KEY ("CURRKEY") REFERENCES "CURRENCY" ("CUR
RKEY") ON DELETE RESTRICT ON UPDATE CASCADE
);
The strangest thing is that I have other similar tables where this works fine!
sqlite> select * from journalhdr where transno=13;
13|Test transaction ATM Withdrawel 20130213|20130223||20130223||
TransNo in that table is also integer (10,0) NOT NULL - this is what makes me thing it is something to do with the values.
Another clue is that the sort order seems to be based on ascii, not numeric:
sqlite> select * from ledger order by acctno;
0|0|0|JPY|11|Root Account|P|X|0|X|0|0|SYSTEM|20121209|150000|0|0|0|
1|0|0|JPY|8|Paid-In Capital|C|X|0|X|0|0||||0|0|0|
10|0|0|USD|20|Sallie Mae|L|X|0|X|0|0|SYSTEM|20121209|153900|0|0|0|
21|0|0|USD|21|Skrill|A|X|0|X|0|0|SYSTEM|20121209|154000|0|0|0|
22|0|0|USD|22|AES|L|X|0|X|0|0|SYSTEM|20121209|154200|0|0|0|
23|0|0|JPY|23|Marui|L|X|0|X|0|0|SYSTEM|20121209|154400|0|0|0|
24|0|0|JPY|24|Amex JP|L|X|0|X|0|0|SYSTEM|20121209|154500|0|0|0|
3|0|0|JPY|13|Mitsubishi Bank Futsuu|A|X|0|X|0|0|SYSTEM|20121209|150000|0|0|0|
Of course the sort order on journalhdr (where the select works properly) is numeric.
Solved! (sort-of)
The data can be fixed like this:
sqlite> update ledger set acctno = 23 where rowid = 13;
sqlite> select * from ledger where acctno = 25;
25|0|0|JPY|0|Test|L|X|0|X|0|0|SYSTEM|20130224|132500|0|0|0|
Still, if it was stored as strings, then that leave a few questions:
1. Why couldn't I select it as a string using the quotes?
2. How did it get stored as a string since it is a valid integer?
3. How would you go about detecting this problem normally besides noticing bizzarre symptoms?
Although the data would normally be entered by my program, some of it was created by hand using Navicat, so I assume the problem must lie there.
You are victim of SQLite dynamic typing.
Even though SQLite defines system of type affinity, which sets some rules on how input strings or numbers will be converted to actual internal values, but it does NOT prevent software that is using prepared statements to explicitly set any type (and data value) for the column (and this can be different per row!).
This can be shown by this simple example:
CREATE TABLE ledger (acctno INTEGER, name VARCHAR(16));
INSERT INTO ledger VALUES(1, 'John'); -- INTEGER '1'
INSERT INTO ledger VALUES(2 || X'00', 'Zack'); -- BLOB '2\0'
I have inserted second row not as INTEGER, but as binary string containing embedded zero byte. This reproduces your issue exactly, see this SQLFiddle, step by step. You can also execute these commands in sqlite3, you will get the same result.
Below is Perl script that also reproduces this issue
This script creates just 2 rows with acctno having values of integer 1 for first, and "2\0" for second row. "2\0" means string consisting of 2 bytes: first is digit 2, and second is 0 (zero) byte.
Of course, it is very difficult to visually tell "2\0" from just "2", but this is what script below demonstrates:
#!/usr/bin/perl -w
use strict;
use warnings;
use DBI qw(:sql_types);
my $dbh = DBI->connect("dbi:SQLite:test.db") or die DBI::errstr();
$dbh->do("DROP TABLE IF EXISTS ledger");
$dbh->do("CREATE TABLE ledger (acctno INTEGER, name VARCHAR(16))");
my $sth = $dbh->prepare(
"INSERT INTO ledger (acctno, name) VALUES (?, ?)");
$sth->bind_param(1, "1", SQL_INTEGER);
$sth->bind_param(2, "John");
$sth->execute();
$sth->bind_param(1, "2\0", SQL_BLOB);
$sth->bind_param(2, "Zack");
$sth->execute();
$sth = $dbh->prepare(
"SELECT count(*) FROM ledger WHERE acctno = ?");
$sth->bind_param(1, "1");
$sth->execute();
my ($num1) = $sth->fetchrow_array();
print "Number of rows matching id '1' is $num1\n";
$sth->bind_param(1, "2");
$sth->execute();
my ($num2) = $sth->fetchrow_array();
print "Number of rows matching id '2' is $num2\n";
$sth->bind_param(1, "2\0", SQL_BLOB);
$sth->execute();
my ($num3) = $sth->fetchrow_array();
print "Number of rows matching id '2<0>' is $num3\n";
Output of this script is:
Number of rows matching id '1' is 1
Number of rows matching id '2' is 0
Number of rows matching id '2<0>' is 1
If you were to look at resultant table using any SQLite tool (including sqlite3), it will print 2 for second row - they all get confused by trailing 0 inside a BLOB when it gets coerced to string or number.
Note that I had to use custom param binding to coerce type to BLOB and permit null bytes stored:
$sth->bind_param(1, "2\0", SQL_BLOB);
Long story short, it is either some of your client programs, or some of client tools like Navicat which screwed it up.

How to autogenerate the username with specific string?

I am using asp.net2008 and MY SQL.
I want to auto-generate the value for the field username with the format as
"SISI001", "SISI002",
etc. in SQL whenever the new record is going to inserted.
How can i do it?
What can be the SQL query ?
Thanks.
Add a column with auto increment integer data type
Then get the maximum value of that column in the table using "Max()" function and assign the value to a integer variable (let the variable be 'x').
After that
string userid = "SISI";
x=x+1;
string count = new string('0',6-x.ToString().length);
userid=userid+count+x.ToString();
Use userid as your username
Hope It Helps. Good Luck.
PLAN A>
You need to keep a table (keys) that contains the last numeric ID generated for various entities. This case the entity is "user". So the table will contain two cols viz. entity varchar(100) and lastid int.
You can then have a function written that will receive the entity name and return the incremented ID. Use this ID concatenated with the string component "SISI" to be passed to MySQL for insertion to the database.
Following is the MySQL Table tblkeys:
CREATE TABLE `tblkeys` (
`entity` varchar(100) NOT NULL,
`lastid` int(11) NOT NULL,
PRIMARY KEY (`entity`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
The MySQL Function:
DELIMITER $$
CREATE FUNCTION `getkey`( ps_entity VARCHAR(100)) RETURNS INT(11)
BEGIN
DECLARE ll_lastid INT;
UPDATE tblkeys SET lastid = lastid+1 WHERE tblkeys.entity = ps_entity;
SELECT tblkeys.lastid INTO ll_lastid FROM tblkeys WHERE tblkeys.entity = ps_entity;
RETURN ll_lastid;
END$$
DELIMITER ;
The sample function call:
SELECT getkey('user')
Sample Insert command:
insert into users(username, password) values ('SISI'+getkey('user'), '$password')
Plan B>
This way the ID will be a bit larger but will not require any extra table. Use the following SQL to get a new unique ID:
SELECT ROUND(NOW() + 0)
You can pass it as part of the insert command and concatenate it with the string component of "SISI".
I am not an asp.net developer but i can help you
You can do something like this...
create a sequence in your mysql database as-
CREATE SEQUENCE "Database_name"."SEQUENCE1" MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 001 START WITH 21 CACHE 20 NOORDER NOCYCLE ;
and then while inserting use this query-----
insert into testing (userName) values(concat('SISI', sequence1.nextval))
may it help you in your doubt...
Try this:
CREATE TABLE Users (
IDs int NOT NULL IDENTITY (1, 1),
USERNAME AS 'SISI' + RIGHT('000000000' + CAST(IDs as varchar(10)), 4), --//getting uniqueness of IDs field
Address varchar(150)
)
(not tested)

Resources