SQLite and Android Insert/Updates on SQLiteDatabase -CompiledStatements- - android

Pretend I have a table with 2 columns. _id and name. _id is the primary key and I do not want to set this value manually. I want to perform an insert of name="john," and let the program create my own _id. I am unclear what "index" to use when inserting and how many question marks to use. Does this code do the job? Should the index for john be 1 or 2?
String TABLENAME = "table";
SQLiteStatement statement = db.compileStatement("INSERT INTO "+TABLENAME+" VALUES(?);");
statement.bindString(1,"john");
statement.executeInsert();
Next, say I want to manually set my own _id value. Would I change the code to:
String TABLENAME = "table";
SQLiteStatement statement = db.compileStatement("INSERT INTO "+TABLENAME+" VALUES(?,?);");
statement.bindLong(1,666); //Manual _id.
statement.bindString(2,"john");
statement.executeInsert();

Your first example where you provide only the name will not work:
sqlite> create table test (i integer primary key autoincrement, j text);
sqlite> insert into test values ('asd');
Error: table test has 2 columns but 1 values were supplied
sqlite> insert into test values (null, 'asd');
sqlite> select * from test;
1|asd
sqlite> insert into test (j) values ('asd');
sqlite> select * from test;
1|asd
2|asd
so you need to identify the name column as the destination of the sole value this way, (or as you mentioned in your comment pass null):
SQLiteStatement statement = db.compileStatement("INSERT INTO "+TABLENAME+" (name) VALUES(?);");
Your second example should work fine.
This would apply to some table created this way:
create table SomeTable (_id integer primary key autoincrement, name text)

Then
SQLiteStatement statement = db.compileStatement("INSERT INTO "+TABLENAME+" VALUES(null,?);");
statement.bindString(1,"john");
Should also work.

Related

Android - Change a column type in SQLite database dynamically at runtime

I have an application, where I am detecting the type of a particular column at run-time, on page load. Please refer the below code:
public String fncCheckColumnType(String strColumnName){
db = this.getWritableDatabase();
String strColumnType = "";
Cursor typeCursor = db.rawQuery("SELECT typeof (" + strColumnName +") from tblUsers, null);
typeCursor.moveToFirst();
strColumnType = typeCursor.getString(0);
return strColumnType;
}
The above method simply detects the type of column with column Name 'strColumnName'. I am getting the type of column in this case.
Now, I want to change the column type to TEXT if I am receiving INTEGER as the column type. For this, I tried the below code:
public String fncChangeColumnType(String strColumnName){
db = this.getWritableDatabase();
String newType = "";
Cursor changeCursor = db.rawQuery("ALTER TABLE tblUsers MODIFY COLUMN " + strColumnName + " TEXT", null);
if (changeCursor != null && changeCursor.moveToFirst()){
newType = changeCursor.getString(0);
}
return newType;
}
But while executing the 'fncChangeColumnType' method, I am getting this error, android.database.sqlite.SQLiteException: near "MODIFY": syntax error (code 1): , while compiling: ALTER TABLE tblUsers MODIFY COLUMN UserID TEXT
NOTE: I also replaced 'MODIFY' with 'ALTER', but still getting the same error.
Please check if this is the right method to change the type dynamically.
Please respond back if someone has a solution to this.
Thanks in advance.
In brief, the solution could be :-
Do nothing (i.e. take advantage of SQLite's flexibility)
you could utilise CAST e.g. CAST(mycolumn AS TEXT) (as used below)
Create a new table to replace the old table.
Explanations.
With SQLite there are limitations on what can be altered. In short you cannot change a column. Alter only allows you to either rename a table or to add a column. As per :-
SQL As Understood By SQLite - ALTER TABLE
However, with the exception of a column that is an alias of the rowid column
one defined with ?? INTEGER PRIMARY KEY or ?? INTEGER PRIMARY KEY AUTOINCREMENT or ?? INTEGER ... PRIMARY KEY(??) (where ?? represents a valid column name)
you can store any type of value in any type of column. e.g. consider the following (which stores an INTEGER, a REAL, a TEXT, a date that ends up being TEXT and a BLOB) :-
CREATE TABLE IF NOT EXISTS example1_table (col1 BLOB);
INSERT INTO example1_table VALUES (1),(5.678),('fred'),(date('now')),(x'ffeeddccbbaa998877665544332211');
SELECT *, typeof(col1) FROM example1_table;
The result is :-
As such is there a need to change the column type at all?
If the above is insufficient then your only option is to create a new table with the new column definitions, populate it if required from the original table, and to then replace the original table with the new table ( a) drop original and b)rename new or a) rename original, b) rename new and c) drop original)
e.g. :-
DROP TABLE IF EXISTS original;
CREATE TABLE IF NOT EXISTS original (mycolumn INTEGER);
INSERT INTO original VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(0);
-- The original table now exists and is populated
CREATE TABLE IF NOT EXISTS newtable (mycolumn TEXT);
INSERT INTO newtable SELECT CAST(mycolumn AS TEXT) FROM original;
ALTER TABLE original RENAME TO old_original;
ALTER TABLE newtable RENAME TO original;
DROP TABLE IF EXISTS old_original;
SELECT *,typeof(mycolumn) FROM original;
The result being :-
i think the sql query statement is wrong ,try
ALTER TABLE tblUsers MODIFY COLUMN id TYPE integer USING (id::integer);
instead of id use column name....
hope this helps....
EDIT:
"ALTER TABLE tblUsers MODIFY COLUMN "+strColumnName+" TYPE integer USING ("+strColumnName+"::integer);"

Can you set a column equal to another column in a table using SQLiteDatabse update()?

I need to make a column equal to another column in the table. I can't figure it out using the update method of my SQLiteDatabase.
I know the SQL statement is:
UPDATE coolTable SET columnA = columnB;
Do I put it in the ContentValues I pass the function? or the selection string?
You can use update() only to set literal values (as bind params), not any other kind of expression supported by sqlite SQL syntax.
Use execSQL() to execute your raw UPDATE query with column name expression.
execSQL() with error checking:
SQLiteDatabase db = getReadableDatabase();
try {
long count = DatabaseUtils.queryNumEntries(db, "pweb");
db.execSQL("update pweb set h_id = _id;");
long rows = DatabaseUtils.longForQuery(db, "SELECT changes()", null);
if(count != rows ) Log.e("wrong count","update failed");
}
catch(SQLException e){
Log.e("SQLException","update failed");
}
db.close();
but I was wondering if it is possible to use the database's update()
function instead of execSQL()
You can use sqlite3 to view and manipulate you data, and test out sql commands.
Create a table:
CREATE TABLE pweb (_id INTEGER PRIMARY KEY,h_id INTEGER ,sent INTEGER);
See the original rows:
sqlite> select * from pweb;
1|10|1
2|20|1
3|30|0
4|40|0
execute a column update:
sqlite> update pweb set h_id = _id;
See the changes to all rows:
sqlite> select * from pweb;
1|1|1
2|2|1
3|3|0
4|4|0
Something more complex ?
sqlite> update pweb set h_id = _id + 1;
result:
sqlite> select * from pweb;
1|2|1
2|3|1
3|4|0
4|5|0
See also Understanding SQLITE DataBase in Android:

Delete specific record in sqlite table based on two criteria: _id and column

I have created a sqlite table for my android app, this table has 5 columns and multiple rows, the columns being: _id, column1, column2, column3, column4.
I want to delete a specific record, for instance the record stored in column3 corresponding to _id (in a different class are the getters and setters, for this I've named the class "TableHandler")
I guess that I'm a bit confused, following is what I was planning, but for column3 I'm not sure what should be the argument, I just want to delete whatever is in that column position corresponding to _id
public void deleteValueColumn3(TableHandler value){
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, KEY_ID + " = ? AND " + KEY_COLUMN3 + " = ?",
new String[] {String.valueOf(value.getID()), ?????????);
db.close();
}
The ???????? is that I'm stuck there, maybe the whole method needs to be rewritten, I would appreciate your input.
Thanks
If you want to delete the whole record, just use the _id of the record in delete method, because that is the primary key for your table and therefore is unique. If you'd rather keep the record, you con always use the SQLiteDatabase.update method, specifying null as the new value that will replace column3 value; check out that column3 declaration has no NOT NULL tag, otherwise that could easily throw exception at you.
SQLite does not allow you to delete columns for a specific row.
You can only delete ROWS of data (delete the row that has the column _ID = 1).
Here's a quick tutorial on SQL.
How about updating that column with a null value, rather than using delete()?
ContentValues cv = new ContentValues();
cv.putNull(KEY_COLUMN3);
db.getWritableDatabase().update(
TABLE_NAME,
cv,
KEY_ID + "=?",
new String[]{String.valueOf(keyIdValue)});

SQlite AUTOINCREMENT with Statement Binding

Created a table
"CREATE TABLE student ( id INTEGER PRIMARY KEY AUTOINCREMENT, name
TEXT, course TEXT)"
Now when trying to insert a row like
String sql = "INSERT INTO student" +" VALUES (?,?)";
SQLiteStatement statement = myWriteableDatabase.compileStatement(sql);
statement.clearBindings();
statement.bindString(2, "Some Name");
statement.bindString(3, "Some Course");
statement.execute();
this throws an exception saying
table student has 3 columns but 2 values were supplied: , while compiling: INSERT INTO student VALUES (?,?);
Why is this exception even though I have made id column as AUTOINCREMENT.
The PRIMARY KEY autogeneration only kicks in if a NULL is inserted into the column.
Either specify the columns you want to insert to:
INSERT INTO student(name,course) VALUES ...
so that the id column gets a NULL default value, or explicitly insert a NULL value, for example
INSERT INTO student VALUES(NULL,?,?)
Also check your bind indices. They are not correct - it's the index of the ? in the query string, not the index of the column in the table.
First you have an error in yours bindString calls, you only have 2 ? signs in your query, the first make reference to the name column and the second ? make reference to the course column.
If you want use the query like this:
INSERT INTO student VALUES ('name', 'course')
you need change your code to (see the query):
String sql = "INSERT INTO student" +" VALUES (NULL, ?,?)";
SQLiteStatement statement = myWriteableDatabase.compileStatement(sql);
statement.clearBindings();
statement.bindString(1, "Some Name");
statement.bindString(2, "Some Course");
statement.execute();
Or you can use this query:
INSERT INTO student (name, course) VALUES ('first', 'second')
In this case you can use this code:
String sql = "INSERT INTO student (name, course)" +" VALUES (?,?)";
SQLiteStatement statement = myWriteableDatabase.compileStatement(sql);
statement.clearBindings();
statement.bindString(1, "Some Name");
statement.bindString(2, "Some Course");
statement.execute();

Why does strftime() insert string into integer column

I have a 'created' column which is INTEGER and this is how I insert sqlite date into it:
ContentValues vals = new ContentValues();
vals.put(Column._CREATED_DATE, "strftime('%s','now')");
db.insert(Table.ARTICLE.name, null, vals);
Unbelievably he inserts strftime('%s','now') string into INTEGER column!
What the heck?
EDIT: when I run insert into article (created) values (strftime("%s","now")) in an SQLite browser, proper integer value is inserted...
Add a default value to your table instead, e.g.
CREATE TABLE article (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
_created_date INTEGER DEFAULT (strftime('%s', 'now'))
);
This will put unix epoch in _created_date if you do not set its column value when creating the row. If you want a timestamp (e.g. 2012-05-07 13:07:58) you define it as
_created_date INTEGER DEFAULT CURRENT_TIMESTAMP

Categories

Resources