Why the excecSQL not accept * in the statement? - android

I'm working on an android project and I have to delete all records in my table:
public void deleteAll(){
SQLiteDatabase db=this.getWritableDatabase();
String req="delete * from "+ TABLE_ENIGME;
db.execSQL(req);
}
But when I call my function deleteAll this exception is reveled :
android.database.sqlite.SQLiteException: near "*": syntax error: delete * from enigme2
So why " * " is innapropriate?

Please have a look at http://www.sqlite.org/lang_delete.html.
Delete does not accept wildcard.
Use
Delete From <table name>
instead

mostly because thats not valid sql syntax. The just omit the star and do
delete from enigme2;

It's inappropriate because it isn't valid SQL syntax. The * is used to denote "all columns" (when SELECTing). Since the DELETE statement is removing entire rows stating "all columns" is meaningless, as it removes the values from all columns for that row by default.

Related

How to do case-insensitive comparison in delete() method of SQLiteDatabase class Android

I am making an Android app in Kotlin with SQLite, and I use the code below to delete a record with 'subject' column.
val rows = db.delete(TABLE_NAME, "subject=?", arrayOf(subject))
It works as intended, e.g. if I provide the subject string "Math", it deletes the record whose subject is "Math".
My question is, how can I delete a record of subject of "math" case-insenstively. I mean, either Math or math should delete the record.
I read somewhere that I can use "COLLATE NOCASE" in SQL statement as
DELETE FROM TABLE_NAME WHERE subject = "math" COLLATE NOCASE;
But as I am using the delete() method of SQLiteDatabase class in Android, I wonder how I can implement the same case-insensitive comparison.
For normal case insensitivity you can use LIKE rather than = e.g.
val rows = db.delete(TABLE_NAME, "subject LIKE ?", arrayOf(subject))
see https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators for a more in-depth explanation and caveats etc.
The following demonstrates using native SQLite using an SQLite tool (Navicat in this case, other tools exist):-
DROP TABLE IF EXISTS example; /* just in case */
CREATE TABLE IF NOT EXISTS example (subject TEXT); /* create the table */
/* Add some testing data */
INSERT INTO example VALUES ('Math'),('MAth'),('math'),('mATH'),('something else');
SELECT * FROM example; /* output the original data (Result 1)*/
DELETE FROM example WHERE subject = 'math'; /* case sensitive delete*/
SELECT * FROM example; /* output the data after deletion (Result 2)*/
DELETE FROM example WHERE subject LIKE 'math'; /* case insensitive deletion */
SELECT * FROM example; /* output the data after deletion (Result 3)*/
/* Cleanup Environment */
DROP TABLE IF EXISTS example;
Resulting in:-
original data
after case sensitive deletion (i.e. just math is deleted)
after the case insensitive deletion (i.e. all rows bar something deleted)
would delete the math row if it hadn't been deleted previously
I read somewhere that I can use "COLLATE NOCASE" in SQL statement as DELETE FROM TABLE_NAME WHERE subject = "math" COLLATE NOCASE;
Then you could use:-
val rows = db.delete(TABLE_NAME, "subject=? COLLATE NOCASE", arrayOf(subject))
Note that the documentation for the 2nd parameter of the delete method says:-
whereClause String: the optional WHERE clause to apply when deleting. Passing null will delete all rows.
without the WHERE keyword itself
WHERE is added by the method, like FROM is added to the tablename (first parameter) and DELETE is added; when building the SQL that is executed).
i.e. the entire clause (as shown above). The WHERE clause expects and expression which can be quite complex see link above and scroll to the top for what an expression can consist of.

Android SQLite additional WHERE condition after MATCH

In Android SQLite i got tabel like this
domainObjectId: String // like '9876543210'
name: String
description: String
I want to use FTS on this to search without worrying about diacritical marks, how ever i want to let user select also by typing part of object ID(ex. last 4 char)
I got select like
`SELECT * FROM tabel LEFT JOIN tabel_fts on tabel_fts.domainObjectId = tabel.domainObjectId WHERE tabel_fts MATCH '3210*' OR tabel.domainObjectId LIKE '%3210%'
But in return i get error
unable to use function MATCH in the requested context (code 1 SQLITE_ERROR);
Is this possible to add additional condition to select with MATCH?
Try to remove "MATCH" into separate "SELECT":
`SELECT * FROM tabel LEFT JOIN (select * from tabel_fts WHERE tabel_fts.domainObjectId MATCH '3210*') as tabel_fts WHERE tabel.domainObjectId LIKE '%3210%' OR table_fts.ID IS NOT NULL
By the way:
In your "WHERE tabel_fts" it seemed you've missed a column name
There is no "ON" condition in tables JOINm just "WHERE". That's OK? May be it would be better to use UNION?

android update database column based on the current column value

In android, SQLiteDatabase has a update function
update(String table, ContentValues values, String whereClause, String[] whereArgs)
new values in put in values
If I want to update a column A by adding one to it, how should I prepare the ContentValues values variable? I don't think the following would work.
cv.put("A", "A" + 1);
I can sure run execSQL with raw sql, but it does not return num of row updated
If you'd execute a raw query, something like this should work to increment the current value in the column:
UPDATE table_name SET column_a = column_a + 1 WHERE _id = 1
(where 1 is just an example to illustrate how to apply it to a specific row)
The same probably wouldn't work with ContentValues, since (as the name indicates) it takes the values to set the column to. That means it needs to have been evaluated before building the ContentValues, whereas with a raw query the value isn't evaluated until the query actually runs on the database.
You can of course retrieve the current value first and then increment that accordingly when issuing an update; that requires a select query first. Quite commonly though, you're working with objects in Java, where the column value for a row is bound up to a member field of the object. If you've got a setup like that, then you probably already have the current value at the moment you want to run an update query.
As such, it would just look somewhat like:
SomeObject object = ...;
cv.put("column_a", object.getSomeValue() + 1);
(where I'm assuming object.getSomeValue() will return an int)
// edit: here's some more examples for the raw query approach:
SQLite - increase value by a certain number
// edit2: You've edited your original question and added:
I can sure run execSQL with raw sql, but it does not return num of
row updated
If knowing how many rows the query changed is a must, then you can potentially leverage the changes() function. It still means you're going to have to run a second query though.
SELECT changes() FROM table_name
The docs say:
The changes() function returns the number of database rows that were
changed or inserted or deleted by the most recently completed INSERT,
DELETE, or UPDATE statement, exclusive of statements in lower-level
triggers. The changes() SQL function is a wrapper around the
sqlite3_changes() C/C++ function and hence follows the same rules for
counting changes.
Alternatively, you could look into the rawQuery() method that takes an SQL statement and returns the result as a Cursor. Not sure if it that even works for an update query, or whether the result would be anything sensible, but if you're really lucky, you may find that Cursor.getCount() gives you the number of affected rows.
To expand upon #MH's solution, there actually is a way to do a raw update AND get back the number of rows updated (because I'm doing the same thing in one of my projects). You have to use a compiled SQLiteStatement and then call the method executeUpdateDelete(). From the documentation:
public int executeUpdateDelete ()
Execute this SQL statement, if the the number of rows affected by execution of this SQL statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
Returns
the number of rows affected by this SQL statement execution.
See the following sample code where I add a new column to my table and then update each column similarly to how you were asking:
db.beginTransaction();
try {
db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN "
+ COLUMN_NAME_LOCALTIME + " INTEGER");
String stmtString = "UPDATE " + TABLE_NAME + " SET "
+ COLUMN_NAME_LOCALTIME + "="
+ COLUMN_NAME_TIME + "+ (" + tzOffset + ")";
SQLiteStatement sqlStmt = db.compileStatement(stmtString);
int rows = sqlStmt.executeUpdateDelete();
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
I'm using a transaction here because in case I add the new column but CANNOT update the values, I want everything to rollback so I can attempt something else.

Android SQL IF / CASE / Update if exists

i've got a big problem with the android Api.
I'm trying to inset some Values in a SQL-Database and if the key already exist i want to update.
normaly with SQL it's no problem but android throws alwas an error.
my code:
"IF EXISTS (SELECT * FROM "+table+" WHERE Name='"+key+"')" +
" UPDATE "+table+" SET (Value='"+Value+"') WHERE Name='"+key+"'" +
" ELSE" +
" INSERT INTO Table1 (Name,Value) VALUES ('"+key+"','"+Value+"')";
the error i alwas get:
09-19 19:56:46.311: E/AndroidRuntime(32454): Caused by:
android.database.sqlite.SQLiteException: near "CASE": syntax error (code 1): , while compiling: CASE WHEN EXISTS (SELECT * FROM Settings WHERE Name='AppVersion')THEN UPDATE Settings SET (Value='0.5 beta') WHERE Name='AppVersion'ELSE INSERT INTO Table1 (Name,Value) VALUES ('AppVersion','0.5 beta')`
I've also tried to use "CASE" but it doesnt work neither.
"CASE WHEN EXISTS (SELECT * FROM "+table+" WHERE Name='"+key+"')" +
"THEN UPDATE "+table+" SET (Value='"+Value+"') WHERE Name='"+key+"'" +
"ELSE INSERT INTO Table1 (Name,Value) VALUES ('"+key+"','"+Value+"')";
Please can anybody tell me how it works.
PS.: sorry for bad english.
SQLite (obviously) does not support the syntax that you are trying to use.
There are basically two options:
Use SQLite's "ON CONFLICT REPLACE" syntax with an INSERT statement
this requires a unique constraint (in this case, on the 'Name' column).
be aware that this will first delete the old row, and then insert a new one.
If delete/insert is unacceptable to you, then you'll probably have to resort to attempting to update first, get the update count, and if it's zero, do the insert.

SQLite delete syntax error

This line, mDatabase.execSQL(sql);, gives me the following error:
{ sqlite returned: error code = 1, msg = near "*": syntax error }
for Delete * from table_name Query
My SQL query is : DELETE * FROM table_name
How can I solve this?
DELETE * FROM table_name is a wrong sql command. Use DELETE from table_name
Syntax error means that basically your statement is spelled wrong and it can not be parsed. In this case error message states where exactly this error occurred - on "*" character. In such case you should go to database documentation and check proper syntax of the command you are trying to use. In case of SQLite it's here. You can find documentation about DELETE statement there, here is the link. It shows you the syntax in graphical way (called syntax diagrams or railroad diagrams) which should be quite easy to follow.
In this case, as mentioned earlier, you just can't specify "*" between DELETE and FROM. This is because you are always deleting whole rows and you can't delete individual selected columns.
If you need to delete the entire table can you use DROP TABLE IF EXISTS then recreate the table

Categories

Resources