I have table contains columns id, name, profession, age, hobby, country, sex. Now I want to update the fields where sex is female and age is 30. All the fields are text (String). First, I am counting all the rows then running a loop to update the rows. Loop is running as per the total rows but rows are not updated... WHY? Where I have done the mistake? Here is my code:
METHODS FOR ANDROID SQLITE DATABASE QUERY:
public void updateUser(String newProfession, String newCountry, String sx, String ag) {
SQLiteDatabase db = this.getWritableDatabase();
String query = "UPDATE "+TABLE_USER+" SET "+KEY_PROFESSION+"='"+newProfession+"', "+KEY_COUNTRY+"='"+newCountry+"' WHERE "+KEY_SEX+"='"+sx+"' AND "+KEY_AGE+"='"+ag+"'";
Cursor cursor = db.rawQuery(query, null);
cursor.close();
db.close();
}
public int countAll() {
String countQuery = "SELECT * FROM " + TABLE_USER;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
int cnt = cursor.getCount();
cursor.close();
db.close();
return cnt;
}
CALLING THE METHODS
public void updateUsersClicked(View view) {
int allData = db.countAll();
for (int i = 0; i < allData; i++) {
db.updateUser("SENIOR ENGINEER", "CANADA", "female", "30");
System.out.println("T H I S I S T H E R E S U L T: " + i);
}
}
Use execSQL() and not rawQuery() for updates.
rawQuery() just compiles the SQL and requires one of the moveTo...() methods on the returned Cursor to execute it. execSQL() both compiles and runs the SQL.
Also consider using ? parameters with bind args in your SQL to avoid escaping special characters and being vulnerable to SQL injection.
You don't need to do the for loop
a single QSL "Update" query is enough if you want to update All the female with age 30.
If you are new to SQL you can view a simple example here:
Simple SQL Update example
If you want to do something else - please edit your question
Related
I'm trying to call user_id from sqlite database but I get this error
android.database.sqlite.SQLiteException: unknown error (code 0 SQLITE_OK): Queries can be performed using SQLiteDatabase query or rawQuery methods only.
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
public Database user_id(){
SQLiteDatabase db = getReadableDatabase();
String query = String.format("SELECT user_id FROM OrderDetails ;");
db.execSQL(query);
Cursor c = db.rawQuery(query, null);
if (c != null && c.moveToFirst()) {
c.moveToFirst();
}
return user_id();
}
Please don't recommend another solution because I'm stuck with this for more than a day and I tried almost all solutions represented in stackoverflow and online
From: https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase#execSQL(java.lang.String)
public void execSQL (String sql) Execute a single SQL statement
that is NOT a SELECT or any other SQL statement that returns
data.
So remove this line:
db.execSQL(query);
The method execSQL() is not used to execute queries that fetch rows, like SELECT statements. You can use it with INSERT, UPDATE, CREATE, etc.
Also, I think that you want to return the user's ids as a Cursor, right?
So why:
public Database user_id()
this returns a Database object (whatever this is).
Change the method to this:
public Cursor user_id(){
SQLiteDatabase db = getReadableDatabase();
String query = "SELECT user_id FROM OrderDetails";
Cursor c = db.rawQuery(query, null);
return c;
}
I'm trying to have an SQLite database in android but I have a problem with that:
I'm trying to update the text value in the "response" column with id 0. The first problem I had was that the string I was using for the update used an apostrophe (') and it had syntax errors because sql closes the string with an '. So I now am using a prepared sql statement for that. The problem now is that the long that is returning gives a -1, so that means that no rows were effected. So how can I update my current string to the row with id=0?
Note: the first string also has an ' but was added using the addData funtion and it didn't give any errors just using db.insert, is that the problem, should I replace all my code with prepared statements?
public boolean addData(String item) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL2, item);
Log.d(TAG, "addData: Adding " + item + " to " + TABLE_NAME);
long result = db.insert(TABLE_NAME, null, contentValues);
//if date as inserted incorrectly it will return -1
if (result == -1) {
return false;
} else {
return true;
}
}
public long updateData(String newName){
SQLiteDatabase db = this.getWritableDatabase();
String sql = "UPDATE json_response SET response=? WHERE ID='0'";
SQLiteStatement statement = db.compileStatement(sql);
statement.bindString(1, newName); // matches second '?' in sql string
long rowId = statement.executeInsert();
return rowId;
}
I have not used prepared statements much so I can't say why that is not working, but why not use the db.update() method? It takes ContentValues as an argument similar to tour addData() method. Give this a shot.
public int updateData(String newName){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("json_response",newName);
int rows = db.update(TABLE_NAME, cv, "ID=0", null);
return rows;
}
[EDIT] update() returns an integer representing the number of rows affected instead of which row was affected. Keep that in mind as your variable name rowId implies that is not what you are looking for.
[EDIT 2] And no, there is no problem with the addData() method that I can see. The apostrophe that was added did not cause an error because ContentValues parameterizes the string values before adding them into the database. Basically, all SQL-like syntax will be ignored when inserting values, which is great for security reasons.
The problem is, I think, that WHERE ID='0' will always fail; what you want is WHERE ID=0
Am just curious, is date a reserved word i SQLite? I have a column which is named date, and trying to run this query:
DELETE FROM cases WHERE date <= date('now','-1 day')
By doing this:
String query = "DELETE FROM cases WHERE date <= date('now','-1 day')";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
boolean found = cursor.moveToFirst();
if(found) {
int result = cursor.getCount();
Log.w("DeleteOldCases: ", "Result: " + Integer.toString(result));
db.close();
}
But the cursor just gives me a false back, when calling moveToFirst. But in my database there are actually rows that are older than one day. Can anybody explain whats wrong here?
Thanks!
Yes it seems to be a reserved word.
look at: http://www.sqlite.org/lang_datefunc.html
date(timestring, modifier, modifier, ...)
It's strange to have a cursors form DELETE statement. Try to split the operation in
SELECT * FROM cases WHERE date <= date('now','-1 day')
then execute your checks
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
boolean found = cursor.moveToFirst();
if(found) {
int result = cursor.getCount();
Log.w("DeleteOldCases: ", "Result: " + Integer.toString(result));
db.close();
}
and then execute the DELETE part
DELETE FROM cases WHERE date <= date('now','-1 day')
This question is quite old but it deserves a proper answer.
No, date is not a reserved word.
The problem with your code is that you are using the method rawQuery() to delete from the table, which is not the way to do it.
rawQuery() should be used to return rows from the table in the form of a Cursor object.
Since your sql statement does not return any rows the method moveToFirst() returns false.
What you should use is the method delete() which returns the number of deleted rows:
int result = db.delete("cases", "date <= date('now', '-1 day')", null);
I have tried this code
Cursor c=db.rawQuery("SELECT name FROM sqlite_master WHERE type = 'table'",null);
c.moveToFirst();
while(!c.isAfterLast()){
Toast.makeText(activityName.this, "Table Name=> "+c.getString(0),
Toast.LENGTH_LONG).show();
}
But it throws the error:
"android.database.sqlite.SQLiteException: no such table: sqlite_master(code 1):, while
compiling: SELECT name FROM sqlite_master WHERE type='table'"
How to fetch all the table names?
Checked, tested and functioning. Try this code:
Cursor c = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
if (c.moveToFirst()) {
while ( !c.isAfterLast() ) {
Toast.makeText(activityName.this, "Table Name=> "+c.getString(0), Toast.LENGTH_LONG).show();
c.moveToNext();
}
}
I am assuming, at some point down the line, you will to grab a list of the table names to display in perhaps a ListView or something. Not just show a Toast.
Untested code. Just what came at the top of my mind. Do test before using it in a production app. ;-)
In that event, consider the following changes to the code posted above:
ArrayList<String> arrTblNames = new ArrayList<String>();
Cursor c = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
if (c.moveToFirst()) {
while ( !c.isAfterLast() ) {
arrTblNames.add( c.getString( c.getColumnIndex("name")) );
c.moveToNext();
}
}
Change your sql string to this one:
"SELECT name FROM sqlite_master WHERE type='table' AND name!='android_metadata' order by name"
To get table name with list of all column of that table
public void getDatabaseStructure(SQLiteDatabase db) {
Cursor c = db.rawQuery(
"SELECT name FROM sqlite_master WHERE type='table'", null);
ArrayList<String[]> result = new ArrayList<String[]>();
int i = 0;
result.add(c.getColumnNames());
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
String[] temp = new String[c.getColumnCount()];
for (i = 0; i < temp.length; i++) {
temp[i] = c.getString(i);
System.out.println("TABLE - "+temp[i]);
Cursor c1 = db.rawQuery(
"SELECT * FROM "+temp[i], null);
c1.moveToFirst();
String[] COLUMNS = c1.getColumnNames();
for(int j=0;j<COLUMNS.length;j++){
c1.move(j);
System.out.println(" COLUMN - "+COLUMNS[j]);
}
}
result.add(temp);
}
}
Try adding the schema before the table
schema.sqlite_master
From SQL FAQ
If you are running the sqlite3 command-line access program you can type ".tables" to get a list of all tables. Or you can type ".schema" to see the complete database schema including all tables and indices. Either of these commands can be followed by a LIKE pattern that will restrict the tables that are displayed.
From within a C/C++ program (or a script using Tcl/Ruby/Perl/Python bindings) you can get access to table and index names by doing a SELECT on a special table named "SQLITE_MASTER". Every SQLite database has an SQLITE_MASTER table that defines the schema for the database. The SQLITE_MASTER table looks like this:
CREATE TABLE sqlite_master (
type TEXT,
name TEXT,
tbl_name TEXT,
rootpage INTEGER,
sql TEXT
);
Try this:
SELECT name FROM sqlite_master WHERE type = "table";
I tested Siddharth Lele answer with Kotlin and Room, and it works as well.
The same code but using Kotlin and Room is something like that:
val cursor = roomDatabaseInstance.query(SimpleSQLiteQuery("SELECT name FROM sqlite_master WHERE type='table' AND name NOT IN ('android_metadata', 'sqlite_sequence', 'room_master_table')"))
val tableNames = arrayListOf<String>()
if(cursor.moveToFirst()) {
while (!cursor.isAfterLast) {
tableNames.add(cursor.getString(0))
cursor.moveToNext()
}
}
I have a database table with multiple columns
I use custom List<> and populate it from database
What i want to do is filter what will go into the list from database depending on user input
for example if i had a table like this:
name|phone|date|address
User can specify any filter(by name, by phone, by date... or all of it) and only items that matches all criteria will go into the list
Is there a way to do this?
Method that returns all items from database
public List<MoviesDatabaseEntry> getAllMovies(String table)
{
List<MoviesDatabaseEntry> lists = new ArrayList<MoviesDatabaseEntry>();
// Select All Query
String selectQuery = "SELECT * FROM " + table;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst())
{
do {
MoviesDatabaseEntry list = new MoviesDatabaseEntry();
list.set_id(Integer.parseInt(cursor.getString(0)));
list.set_title(cursor.getString(1));
list.set_runtime(cursor.getString(2));
list.set_rating(cursor.getDouble(3));
list.set_genres(cursor.getString(4));
list.set_type(cursor.getString(5));
list.set_lang(cursor.getString(6));
list.set_poster(cursor.getString(7));
list.set_url(cursor.getString(8));
list.set_director(cursor.getString(9));
list.set_actors(cursor.getString(10));
list.set_plot(cursor.getString(11));
list.set_year(cursor.getInt(12));
list.set_country(cursor.getString(13));
list.set_date(cursor.getInt(14));
// Adding to list
lists.add(list);
} while (cursor.moveToNext());
}
// return list
db.close();
cursor.close();
return lists;
}
You can filter the entries you get in the SQL query you are building in this line:
String selectQuery = "SELECT * FROM " + table;
To filter the dataset your retrieve, you would add a WHERE clause to it. When you would, for example, only want those entries where the rating is over 3, you would change this to:
String selectQuery = "SELECT * FROM " + table + " WHERE rating > 3";
SQL is a very powerful language which offers a lot of possibilities. It's an essential skill when you work with relational databases. When you want to learn it, I can recommend you the interactive tutorial website http://sqlzoo.net/
You have to change your database query for getting specific data from the query.
You have one function that returns all rows from database like so: getAllMovies(String table)
Here you are using:
String selectQuery = "SELECT * FROM " + table;
Make a new function like this:
public List<MoviesDatabaseEntry> getSelectedMovies(String table)
{
List<MoviesDatabaseEntry> lists = new ArrayList<MoviesDatabaseEntry>();
Cursor cursor = db.query(true, TABLE_NAME, new String[] { <your row names> },
**check condition(as string)**, null,
null, null, null, null);
...
}
Now just call this function when required with your specific query string
Make as many functions as you want!