how to store syntax in sqlite - android

1.which data type should be used to store data like group=AB+ ?
E/SQLiteLog: (1) near "group": syntax error SQLiteDatabase:
Error inserting
district=jhapa phone=9843284985 name=Tom group=AB+
My table is in this format
CREATE TABLE IF NOT EXISTS `Doners` (\n" +
"\t`name`\tTEXT,\n" +
"\t`phone`\tNUMERIC,\n" +
"\t`group`\tBLOB,\n" +
"\t`district`\tTEXT\n" +
");";

For Android you can either use
- native SQL via the SQLiteDatabase execSQL method
- the SQLiteDatabase convenience insert family of methods :-
insert (effectively INSERT OR IGNORE)
insertOrThrow (standard INSERT)
insertWithOnConflict
SQLiteDatabase - insert
So assuming that you want to insert :-
Tom into the name column,
9843284985 into the phone column,
AB+ into the group column,
NOTE that group is an SQLite keyword and therefore cannot be used and will result in a syntax error, unless it is enclosed SQL As Understood By SQLite - SQLite Keywords
jhapa
And that the variable db is an instantiated instance of the SQliteDatabase class then :-
you could use :-
db.execSQl("INSERT INTO `Doners` VALUES('Tom',9843284985,'AB+','jhapa')");
noting that a value must be provided for all the defined columns and that the values should be in the order that the columns were defined in.
or you could use :-
db.execSQL("INSERT INTO Doners (district,phone,name,`group`) VALUES ('jhapa','9843284985','Tom','AB+')");
Here you specify the columns into which the values will be placed, you can specify them in what order you like (values will be inserted according to the order), you can also omit columns (dependant upon the column definition)
Defining a column as NOT NULL would require a column and value. However, if a DEFAULT value has been defined as well as NOT NULL then the column can be omitted.
you could use the insert convenience method like :-
ContentValues cv = new ContentValues();
cv.put("phone","9843284985");
cv.put("name","Tom);
cv.put("`group`","AB+");
cv.put("district","jhapa");
long rowid = db.insert("Doners",null,cv);
rowid will be the rowid of the inserted row (a unique identifier of the row) or if no row was inserted then -1.
the convenience method :-
it builds the SQL on your behalf
protects against SQL injection
encloses values accordingly
suitable encodes byte[]'s into the the x'ff00fe.......' used by SQL.
returns the rowid (executes a query using last_insert_rowid()).
in regards to :-
which data type should be used to store data like group=AB+ ?
Due to SQLite's flexibility it probably does not matter what type is assigned to the column. That is with the exception of the rowid or an alias of the rowid (the_column INTEGER PRIMARY KEY makes the_column an alias of the rowid column) any type of data can be stored in any type of column and to further expand on the flexibility type can be virtually anything (keywords and other syntactically confusing values excepted).
As such CREATE TABLE mytable (mycolumn RUMPLESTILTSKIN) is valid (column has numeric affinity). see - Datatypes In SQLite Version 3

Related

how can we get the id of a row that we insert through code

I need to retrieve the id of the row inserted just now. ie, i have a table for words and a table for meaning. i need the wordId of the word i insert in the table for words and that wordId is used for inserting the meaning in meaning table. Can anyone help me out??
I thought i could use trigger and tried the trigger:
"CREATE TRIGGER IF NOT EXISTS word_insert_trigger AFTER INSERT ON tb_words BEGIN select NEW.word_id from tb_words; END;"
like this. i tried this in sqlite dbbrowser. but it didn't work out.
i need the row id when i insert a row like this :"insert into tb_words(word_name) values('test');"
How can i do that without using "SELECT last_insert_rowid()"? like in the following link:
How to retrieve the last autoincremented ID from a SQLite table?
No need for a trigger. Use the SQliteDatabase insert method. It returns the id (as a long) (more correctly it returns the rowid and assuming that the word_id column has been defined as an alias of the rowid column, then the returned value will be the value assigned to the word_id column).
An alias of the rowid column is defined if word_id INTEGER PRIMARY KEY is coded (the AUTOINCREMENT key may be used BUT in generally should not be used).
You may wish to read SQLite AUTOINCREMENT and/or Rowid Tables
Instead of something like :-
db.execsql("insert into tb_words(word_name) values('test');");
You would use something like :-
ContentValues cv = new ContentValues();
cv.put("word_name","test");
long word_id = db.insert("tb_words",null,cv);

SQLite - integer PRIMARY INDEX constraint failing?

In my Android app, I create a FULLTEXT table like this:
CREATE VIRTUAL TABLE products USING fts3 (
_id integer PRIMARY KEY,
product_name text NOT NULL,
...
)
And I add this index:
CREATE INDEX product_name_index ON products (product_name)
The app populates the table with various products, each with a unique _id value.
However, when I then try to insert an already-existing product ID (using an _id value that is already in the table, but with a different product_name value) like this:
long rowId = db.insertOrThrow("products", null, contentValues);
a new row is added to the table (with a brand new rowId value returned)!
I expected the insertOrThrow command to fail, so where am I going wrong? Is it something to do with the fact that it's a FULLTEXT table or could the index I specified on the product_name column be messing things up somehow?
I read this section about INTEGER PRIMARY KEY, but unfortunately I'm none the wiser.
Update
When I try to perform the same operation on a standard (non-FULLTEXT) table, then the insertOrThrow command results in the expected SQLiteConstraintException.
I think the issue might be that an FTS table has the concept of a docid and a rowid column and specifying null for the docid results in that being given a value.
as per :-
There is one other subtle difference between "docid" and the normal
SQLite aliases for the rowid column.
Normally, if an INSERT or UPDATE
statement assigns discrete values to two or more aliases of the rowid
column, SQLite writes the rightmost of such values specified in the
INSERT or UPDATE statement to the database.
However, assigning a
non-NULL value to both the "docid" and one or more of the SQLite rowid
aliases when inserting or updating an FTS table is considered an
error. See below for an example.
1.3. Populating FTS Tables

SQLite limit is a string

The Android API docs appear to suggest that the limit clause to provide when querying a SQLite database is a string.
This does not make much sense to me.
Presumably, it is converted internally to an integer?
Or are there other issues involved here?
I think they key thing to consider is that the parameter isn't solely for the single 1st part (see expr1 below) but for the entire LIMIT Clause.
This clause can be as as simple as just a single integer, but it can also be relatively complex; the full syntax of a LIMIT Clause is :-
LIMIT expr1 OFFSET (or ,) expr2; see - SELECT
Where :-
expr1 should resolve to an integer specifying the maximum number of rows to be returned and
expr2 is an integer that specifies the offset (where 1 is the 1st) from the start of the potential rows to be returned.
either expression could, at least in theory, be a subquery e.g.
String limit_clause = "(SELECT numbertoshow FROM types WHERE id = (random() & 1)+1)";
P.S. not saying this is a useful example rather it is an example that works and is for illustration of a complex LIMIT clause and as such an example of why a String as opposed to an Integer is the more flexible/useful parameter type.
The complete SQL used for testing the above was :-
/*
DROP TABLE IF EXISTS basetable;
CREATE TABLE IF NOT EXISTS basetable (basename TEXT);
INSERT INTO basetable VALUES('test001');
INSERT INTO basetable VALUES('test002');
INSERT INTO basetable VALUES('test003');
INSERT INTO basetable VALUES('test004');
INSERT INTO basetable VALUES('test005');
INSERT INTO basetable VALUES('test006');
INSERT INTO basetable VALUES('test007');
INSERT INTO basetable VALUES('test008');
INSERT INTO basetable VALUES('test009');
INSERT INTO basetable VALUES('test010');
INSERT INTO basetable VALUES('test011');
INSERT INTO basetable VALUES('test012');
DROP TABLE IF EXISTS types;
CREATE TABLE IF NOT EXISTS types (id INTEGER PRIMARY KEY, typename TEXT, numbertoshow INTEGER);
INSERT INTO types VALUES(null,'type001',3);
INSERT INTO types VALUES(null,'type002',4);
*/
SELECT * FROM basetable LIMIT (SELECT numbertoshow FROM types WHERE id = (random() & 1)+1);
Note commented out statements are commented out as they are just needed the once.

Cursor.getType() returns FIELD_TYPE_NULL if all the rows are null for a particular column

I am creating a table using the following query:
private static final String SQL_CREATE_ENTRIES = "CREATE TABLE person_info ( uniqueId INTEGER,first_name TEXT,last_name TEXT,
address TEXT)";
sqLiteDatabase.execSQL(SQL_CREATE_ENTRIES);
I am inserting the values as follows:
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put("first_name", "Anshul");
values.put("last_name", "Jain");
values.put("address", "Bangalore");
return db.insert(TABLE_NAME, null, values);
Note that I am not giving any value for uniqueId column. Thus, uniqueId column values are null.
When I query the database and try to the type of each column using cursor.getType(i), it returns Cursor.FIELD_TYPE_NULL for uniqueId column. According to the documentation, if all the column values are null, then it will return this value. But ideally it should return Cursor.FIELD_TYPE_INTEGER because that's what I declared while creating the database.
Is there any other way of retrieving the correct column type when all the values of a column are null.
Most SQL database engines (every SQL database engine other than
SQLite, as far as we know) uses static, rigid typing. With static
typing, the datatype of a value is determined by its container - the
particular column in which the value is stored.
SQLite uses a more general dynamic type system. In SQLite, the
datatype of a value is associated with the value itself, not with its
container.
SQLite Docs
This behavior of returning Cursor.FIELD_TYPE_NULL(which according to you is not ideal) is absolutely ideal because SQLite is designed in that way only.
Querying the database to get the type of a Container using cursor.getType(i) will only work if the Container is not NULL otherwise it returns Cursor.FIELD_TYPE_NULL (as in your case).
You can use PRAGMA table_info(table_name) for retrieving the datatype.
Check this SO answer -- Getting the type of a column in SQLite

Android Sqlite INSERT error when table contains only _id

I have a SQLite table that contains only the _id:
"create table rule (_id integer primary key);";
When running this set of commands:
ContentValues initialValues = new ContentValues();
mDb.insert(TABLE, null, initialValues)
I obtain the following exception:
android.database.sqlite.SQLiteException: near "null": syntax error (code 1): , while compiling: INSERT INTO rule(null) VALUES (NULL)
The initial error occurs because ContentValues cannot be empty. Android provides a convenience parameter called nullColumnHack that allows you to pass a single column with the value null, to bypass this problem.
However this doesn't apply in my case because the row id (_id) cannot be null! Based on the syntax found in the SQLite language docs, I would like to be able to run the SQLite code:
INSERT INTO rule DEFAULT VALUES;
How can i achieve something like this using the android insert method? Or is there something I need to add to my create statement?
UPDATE: In the situation where a table contains ONLY a rowid, the proper syntax is to use INSERT INTO __ DEFAULT VALUES.
The sqlite insert method listed in android does not support DEFAULT VALUES as an option.
A bug has been filed with google and to get support for default values the following commands would need to be executed:
mDb.execSQL("INSERT INTO rule DEFAULT VALUES;");
Cursor c = mDb.rawQuery("SELECT last_insert_rowid()",null);
c.moveToFirst();
int rowid = c.getInt(0);
As stated in the accepted answer, we can get around this (and DEFAULT VALUES) by using nullHackColumn and assigning the row id (_id) to null and letting SQLite make the conversion from null to the auto-incremented value.
As jeet mentioned you can provide nullColumnHack as a second parameter. And as you yourself mentioned autoincrement isn't necessary to increment a value of primary key.
So the syntax:
insert into rule (_id) values(null)
where _id is primary key and autoincremented value is correct for sql. I think most SQL databases will replace null with new incremented value, at least MySQL, SQLite and Oracle can do this
Thus:
ContentValues cv = new ContentValues();
db.insert("rule", "_id", cv);
should give you desired results.
You need to add autoincrement to your create table query like:
"create table rule (_id integer primary key autoincrement);";
In your case you need to manually set the ID of the row with each insert. this way it will increment it automatically when you insert an empty row as you did in your case.
Try this way :
ContentValues initialValues= new ContentValues();
if(check here --id is null----)
{
initialValues.put("_id", "0");
}
else
{
initialValues.put("_id", id);
}
mDb.insert(TABLE, null, initialValues)
Check following:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert(java.lang.String, java.lang.String, android.content.ContentValues)
SQL doesn't allow inserting a completely empty row without naming at least one column name. If your provided values is empty, no column names are known and an empty row can't be inserted. If not set to null, the nullColumnHack parameter provides the name of nullable column name to explicitly insert a NULL into in the case where your values is empty.
the insert needs a null value you just have to put
db.insert ("people", null, c);

Categories

Resources