The second parameter of insert method of SQLiteDatabase is "nullColumnHack". WHat does this refers. What value should be passed to this parameter.
Thanks
Let's suppose you have a table named foo where all columns either allow NULL values or have defaults.
In some SQL implementations, this would be valid SQL:
`INSERT INTO `foo;
That's not valid in SQLite. You have to have at least one column specified:
INSERT INTO foo (somecol) VALUES (NULL);
Hence, in the case where you pass an empty ContentValues to insert(), Android and SQLite need some column that is safe to assign NULL to. If you have several such columns to choose from, pick one via the selection mechanism of your choice: roll of the dice, Magic 8-Ball(TM), coin flip, cubicle mate flip, etc.
Personally, I'd've just made it illegal to pass an empty ContentValues to insert(), but they didn't ask me... :-)
courtesy commonsware.
nullColumnHack 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.
Brief explanation..
nullColumnHack
optional; may be null. 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.
Related
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
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
This is a short snippet I found:
"Deleting data
Once data is no longer needed it can be removed from the database with
the delete() method. The delete() method expects 3 parameters, the
database name, a WHERE clause, and an argument array for the WHERE
clause. To delete all records from a table pass null for the WHERE
clause and WHERE clause argument array.
db.delete("tbl_states", "id=?", new String[] {Long.toString(countryId)});
Simply call the delete() method to remove records from the SQLite database. The delete method expects, the table name, and optionally a
where clause and where clause argument replacement arrays as
parameters. The where clause and argument replacement array work just
as with update where ? is replaced by the values in the array."
As usual I cannot find simple documentation as to:
How do I delete everything in the given table (I do not want to use .execSQL) via the .delete() method
What does it return? A cursor or interger? boolean?
Passing in null to the WHERE clause and argument array will delete everything (think if there is no WHERE clause all you are saying is delete from tbl_states).
delete returns the number of rows deleted as an integer.
This line, from your description, answers your first question:
...To delete all records from a table pass null for the WHERE clause
and WHERE clause argument array
db.delete("tbl_states", null, null);
The second answer: it returns the number of rows affected (or deleted, in integer) from the table. Say, you have 20 records in your "tbl_states" table, then, firing the above query will return 20 as integer.
int values = db.delete("tbl_states", null, null);
I'm doing the following to insert information into the database:
ContentValues attachTags = new ContentValues();
attachTags.put("word_fk", "SELECT id FROM entry WHERE ent_seq = " + String.valueOf(line).substring(1));
attachTags.put("tag_id", gTagID);
// Insert the record
Uri insertUri = contentProvider.insert(Uri.parse(mContentProvider.CONTENT_URI + mContentProvider.PATH_SET_TAGS_ON_WORD), attachTags);
Unfortunately, word_fk is literally set to SELECT id FROM entry WHERE ent_seq = 1157170, like so:
id | word_fk | tag_id
52 SELECT id FROM entry WHERE ent_seq = 1157170 4
I intended for word_fk to be set to whatever is returned from the subquery, but it seems as though insert() doesn't execute subqueries when it inserts information into a database. I guess it's related to SQL input sanitization? In any case, how do I make this insert() query work?
I intended for word_fk to be set to whatever is returned from the
subquery, but it seems as though insert() doesn't execute subqueries
when it inserts information into a database. I guess it's related to
SQL input sanitization?
A ContentValues object is a simple map between some columns and the values, so you can't really use it to make sub queries, the data is used as it is.
However, it seems you control the ContentProvider so I don't see why you can't simply extract the sub-query from the ContentValues passed in the insert() method from the word_fk key and further use it directly to obtain what you want. Another approach would be to require that the Uri passed to the insert() method of the provider must contain an additional identifier(the ent_seq parameter in your example) if the word_fk is present in the ContentValues used.
The Android SDK has some convenience methods for manipulating data with SQLite. However both the insert and replace methods use some nullColumnHack parameter which usage I don't understand.
The documentation explains it with the following, but what if a table has multiple columns that allow NULL? I really don't get it :/
SQL doesn't allow inserting a completely empty row, so if initialValues is empty, this column [/row for replace] will explicitly be assigned a NULL value.
Let's suppose you have a table named foo where all columns either allow NULL values or have defaults.
In some SQL implementations, this would be valid SQL:
INSERT INTO foo;
That's not valid in SQLite. You have to have at least one column specified:
INSERT INTO foo (somecol) VALUES (NULL);
Hence, in the case where you pass an empty ContentValues to insert(), Android and SQLite need some column that is safe to assign NULL to. If you have several such columns to choose from, pick one via the selection mechanism of your choice: roll of the dice, Magic 8-Ball(TM), coin flip, cubicle mate flip, etc.
Personally, I'd've just made it illegal to pass an empty ContentValues to insert(), but they didn't ask me... :-)