I'm trying to delete a row from a table in SQLite for the first time, I thought I'd followed a tutorial and adapted it to my app but I've messed up the syntax somewhere.
Here is the code from DatabaseHelper.java
public void deleteRow (String subject) {
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("delete from " + TABLE_NAME +" where " + COL_2 + "=" + subject);
}
And the code that calls it from SubjectActivity.java:
public void onClick(View view) {
if(view.getId()==R.id.deleteSubject) {
Bundle extras = getIntent().getExtras();
String subject = extras.getString("subject");
myDb.deleteRow(subject);
}
}
The row should be deleted when a delete button is pressed in the subject activity, but when I do press the button, the app force closes. What am I missing in the syntax?
This is what your current raw query being passed to SQLite looks like:
delete from TABLE_NAME where COL_2 = some_subject
In other words, you are comparing COL_2 against some_subject, which SQLite will interpret as a column, but not as a string literal. Here is the query you intended to run:
delete from TABLE_NAME where COL_2 = 'some_subject'
The best fix here is to use prepared statements, where the query has a positional parameter (?) for the subject string. The statement will automatically take care of escaping the string on your behalf.
public void deleteRow (String subject) {
SQLiteDatabase db = this.getWritableDatabase();
String sql = "DELETE FROM " + TABLE_NAME + " WHERE " + COL_2 + " = ?";
SQLiteStatement statement = db.compileStatement(sql);
statement.bindString(1, subject);
int numRowsDeleted = statement.executeUpdateDelete();
// you might want to check the number of records which were actually deleted
}
Note that it is not very typical to make the table and column names variable for a given statement. Instead, you would usually see these being hard coded. The reason for this is that it is unlikely that you would want to run the same statement on a different table, or the same table but with different columns.
check below code
public void deleteRow (String subject) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME , COL_2 + "=" + subject, null);
}
Related
I have implemented an SQLite DB into my app and i am trying to write functions that will retrieve the data in a row associated with the unique identifier. I have tried a lot of stackoverflow answers and none seem to be working in my situation.
I have a database helper class where i have created the database through code and am writing the functions. See code below:
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "TrackerNew.db";
public static final String TABLE_NAME = "tracker_new_table";
public static final String COL_2 = "LINETYPE";
public static final String COL_3 = "PACKAGETYPE";
public static final String COL_4 = "QUANTITY";
public static final String COL_5 = "DURATION";
public static final String COL_6 = "STARTTIME";
public static final String COL_7 = "ENDTIME";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1); }
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + TABLE_NAME +" (LINETYPE TEXT PRIMARY KEY,PACKAGETYPE TEXT,QUANTITY TEXT,DURATION TEXT,STARTTIME TEXT,ENDTIME TEXT)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME);
onCreate(db);
}
public boolean insertData(String linetype, String packagetype, String quantity, String duration, String starttime, String endtime) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL_2,linetype);
contentValues.put(COL_3,packagetype);
contentValues.put(COL_4,quantity);
contentValues.put(COL_5,duration);
contentValues.put(COL_6,starttime);
contentValues.put(COL_7,endtime);
long result = db.insert(TABLE_NAME,null,contentValues);
if(result == -1)
return false;
else
return true;
}
//FUNCTIONS TO GET DATA BY ROW
public Cursor getAllData() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.rawQuery("select * from "+TABLE_NAME,null);
return res;
}
public Cursor getProgressBar1() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.query("select * from "+ TABLE_NAME + "where" + COL_2="S1");
return res;
}
public Cursor getProgressBar2() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.query("select * from "+ TABLE_NAME + "where" + COL_2="S2");
return res;
}
}
If you can see my functions at the bottom of my code i am trying to write raw queries to get the data by ID( S1,S2 Etc.)
Can anyone help me out with the code inside these functions?
Thanks!
The issue is that you are trying to create a string using:-
"select * from "+ TABLE_NAME + "where" + COL_2="S1"
This will not compile because you have misplaced the = and overwritten or omitted the + concatenation. I believe that you should have (see later):-
"select * from "+ TABLE_NAME + "where" + COL_2 + "=S1"
(+ added after COL_2 and = moved inside the quotes.
However I then believe that this would fail because you have omitted spaces before and after where, so the above would then resolve to:-
select * from tracker_new_tablewhereLINETYPE = S1
With spaces around where as per :-
"select * from "+ TABLE_NAME + " where " + COL_2 + "=S1"
It will then resolve to :-
select * from tracker_new_table where LINETYPE=S1
However, SQLite will then fail as S1 is not numeric and thus must be in quotes, so you need to actually code :-
"select * from "+ TABLE_NAME + " where " + COL_2 + "='S1'"
However coding :-
public Cursor getProgressBar1() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.query("select * from "+ TABLE_NAME + "where" + COL_2="S1");
return res;
}
Will then fail as the Cursor query method expects at least 7 parameters, as per :-
query(String table, String[] columns, String selection, String[]
selectionArgs, String groupBy, String having, String orderBy)
Query the given table, returning a Cursor over the result set.
SQLiteDatabase
So to use the query method the parameters would be:-
1) The name of the table to be queried so db.query(TABLE_NAME ......
2) A string array of the column names to extract, null means all and equates to *, so db.query(TABLE_NAME,null ......
3) The selection string (SELECT clause) (which can include placeholders i.e ? as per 4th parameter). Without place holders db.query(TABLE_NAME,null,COL_2 + "='S1'", or with a placeholder (generally considered the preferred method), db.query(TABLE_NAME,null,COL_2 + "=?" ......
4) The values to replace the placeholder(s) on a use once basis. So for a single place holder new String[]{"S1"} could be used, so the code now becomes db.query(TABLE_NAME,null,COL_2 + "=?",new String[]{"S1"} ......
5) A GROUP BY clause, null if not using one.
6) A HAVING clause, null if not using one.
7) An ORDER BY clause, null it not using one.
(Note clauses do not have the respective KEYWORDS the query method inserts them it also handles escaping/quoting)
The full query could/should be:-
Cursor res = db.query(TABLE_NAME,null,COL_2 + "=?",new String[]{"S1"},null,null,null);
Finally
And the ProgressBar1 method would be:-
public Cursor getProgressBar1() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.query(TABLE_NAME,null,COL_2 + "=?",new String[]{"S1"},null,null,null);
return res;
}
Edit after comment
As you want to also search for "S2" and "S3" then perhaps a single method could cope e.g.
public Cursor getProgressBar(String linetype) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.query(TABLE_NAME,null,COL_2 + "=?",new String[]{linetype},null,null,null);
return res;
}
Then for progress bar 1 you could use:-
Cursor progressbar1 = getProgressbar("S1");
for progress bar 2
Cursor progressbar2 = getProgressbar("S2");
etc
You could also shorten the getProgressBar method to :-
public Cursor getProgressBar(String linetype) {
SQLiteDatabase db = this.getWritableDatabase();
return db.query(TABLE_NAME,null,COL_2 + "=?",new String[]{linetype},null,null,null);
}
or even :-
public Cursor getProgressBar(String linetype) {
return this.getWritableDatabase().query(TABLE_NAME,null,COL_2 + "=?",new String[]{linetype},null,null,null);
}
Just try to modify this query:
Cursor res = db.query("select * from "+ TABLE_NAME + "where" + COL_2="S1");
to:
Cursor res = db.rawQuery("select * from "+ TABLE_NAME + " where " + COL_2 + " = ?", new String[] {"S1"});
and in getProgressBar2() method too. For more info look to https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
I am learing to code and made a stopwatch that saves the laptimes in a String and gets the date as a String as well. I want to put those in a SQLite database (so i can later display the date in a listview and open it in another activity that shows all the laptimes.) I've followed some of the codes on the internet and try to put stuff together so I might look over some things in my code. I've commented on the parts I think i understand so you can follow my thinking a bit.
The problem: when i press save the following code is executed and returns the toastmessage: Somehting went wrong.
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String dateStamp = getCurrentTimeStamp();
AddData(dataInput, dateStamp);
//DatabaseHelper.deleteAll();
}
}); //save data though AddData method as input the listText
The method AddData is as follows:
public void AddData(String time, String date) {
boolean insertData = DatabaseHelper.addData(time, date);
if (insertData) {
toastMessage(dataInput);
} else {
toastMessage("Something went wrong");
}
}
The boolean method in the DatabaseHelper class is this:
public boolean addData(String times, String date) { //addData that takes a string
SQLiteDatabase db = this.getWritableDatabase(); //database called db and use getWritableDatabase method
ContentValues contentValues = new ContentValues(); //make a new object of ContentValues
contentValues.put(COL_2, times); //put COL_2 and the String in the ContentValues object
contentValues.put(COL_3, date);
long result = db.insert(TABLE_NAME, null, contentValues); //insert contentValues object into the table
//if date as inserted incorrectly it will return -1
if (result == -1) {
db.close();
return false;
} else {
return true;
}
}
It works when i input just 1 variable in addData() but not with 2 that I later implemented. I think it should work. Below I also put the code that is used to make the SQLite Database.
public static final String TABLE_NAME = "stopwatch"; //make a table with name
public static final String COL_1 = "ID"; //make an ID for every colomn
public static final String COL_2 = "times"; //make a 2nd colomn for data
public static final String COL_3= "date";
public DatabaseHelper(Context context) {
super(context, TABLE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) { //make the onCreate method that takes the database as input
String createTable = "CREATE TABLE " + TABLE_NAME + " ( " + COL_1 + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COL_2 +" TEXT" + COL_3 +" TEXT)"; //create the table with SQL statements to input the data correctly
db.execSQL(createTable); //input the SQL statements in the DB
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //make upgrade method that takes the database and the versions
db.execSQL("DROP IF TABLE EXISTS " + TABLE_NAME); //execute SQL statements drop table and which one
onCreate(db); //run through create method
}
I hope someone can help me to find the problem so I can learn more.
Your create table query is missing a comma after the COL_2 +" TEXT"
#Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + TABLE_NAME + " ( " + COL_1 + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COL_2 +" TEXT, " + COL_3 +" TEXT)"; // Added a comma after the COL_2
db.execSQL(createTable);
}
I can see one problem from a quick glance and that is a missing comma in your creation statement which would mean that your database was not created as you intended. Try the below amendment.
String createTable = "CREATE TABLE " + TABLE_NAME + " ( " + COL_1 + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COL_2 +" TEXT," + COL_3 +" TEXT)";
Hello I am using a sqlite database in my android application, and I have question:
I am trying to get the last value text(thats the collumn) from the last row from the table TABLE_XYZ... but it does not work.. i am using the following code...what am I doing wrong?
another question is, how can I return two values instead of only one, when I want to get several values from the last row like column text and message?
private static final String KEY_MESSAGE = "message";
private static final String KEY_TEXT = "text";
...
String selectQuery= "SELECT * FROM " + TABLE_XYZ+" ORDER BY column DESC LIMIT 1";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
cursor.close();
return cursor.getString( cursor.getColumnIndex(KEY_TEXT) );
EDIT:
i hade some errors in my Query,, i fixed it, but still have errors:
String selectQuery= "SELECT * FROM " + TABLE_XYZ + " ORDER BY " + KEY_TEXT+ " DESC LIMIT 1";
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
String str = cursor.getString( cursor.getColumnIndex(KEY_TEXT );
cursor.close();
return str;
while debugging I can see that cursor does have the right values inside... but when i try to get the column value with this command "cursor.getString( cursor.getColumnIndex(KEY_TEXT );"... it does not work...
you are closing cursor before getting it's value
try this :
String selectQuery= "SELECT * FROM " + TABLE_XYZ+" ORDER BY column DESC LIMIT 1";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
String str = "";
if(cursor.moveToFirst())
str = cursor.getString( cursor.getColumnIndex(KEY_TEXT) );
cursor.close();
return str;
From the android documentation: http://developer.android.com/reference/android/database/Cursor.html
abstract void close()
Closes the Cursor, releasing all of its resources and making it completely invalid.
You are closing the cursor before returningthe string.
Like #whatever5599451 said you should not close the cursor before you get value. Also try a query like this:
String selectQuery = "SELECT column FROM " + TABLE_XYZ +
" ORDER BY column DESC LIMIT 1";
You can specify the columns also specify to return only 1 row.
This will bring back only the column you are ordering by you can also specify more columns example:
String selectQuery = "SELECT column, column2, column3 FROM " + TABLE_XYZ +
" ORDER BY column DESC LIMIT 1";
* means select all columns
to get the last column, use the name of the column instead of " * " (* means all, all the fields)
#Steve: do this:
String selectQuery= "SELECT " + KEY_TEXT + " FROM " + TABLE_XYZ + " ORDER BY " + KEY_TEXT+ " DESC LIMIT 1";
then you get just one String with the last record containing just the right column
I have a database with product name,product price and product counter.
Product name is unique,product price gets replaced everytime a new value is entered and the problem is the product counter.
Its default value is 1,when a new product is entered his value is set to 1.I need it to increment whenever there is a conflict for the product name.So if Cheese is entered twice,the counter will say 2 and so on.
What i need it to do is when there is a conflict,add 1 to its value. I want to do it this way because i'll need this later.I'll need to add the inputed value to the table value on some other thing i plan to implement in my app.
How can i achieve this ? I'd like to keep doing it the way i'm doing it now,with the contentvalues method of inserting and not with the sqlite syntax(INSERT,SELECT,etc).Is that even possible ? Cuz i'm an absolute 0 at sqlite syntax.And also,i need it to have a method that i can call in other activities to insert into the database (like insertCountry(Japan,10))
public class SQLiteCountryAssistant extends SQLiteOpenHelper {
private static final String DB_NAME = "usingsqlite.db";
private static final int DB_VERSION_NUMBER = 1;
private static final String DB_TABLE_NAME = "countries";
private static final String DB_COLUMN_1_NAME = "country_name";
private static final String DB_COLUMN_2_NAME = "country_price";
private static final String DB_COLUMN_3_NAME = "country_counter";
private static final String DB_CREATE_SCRIPT = "create table "
+ DB_TABLE_NAME
+ " (_id integer primary key autoincrement, country_name text UNIQUE ON CONFLICT REPLACE,country_price text,country_counter integer default '1' );)";
And this is how i insert :
public void insertCountry(String countryName, String countryPrice) {
sqliteDBInstance.execSQL("INSERT INTO " + DB_TABLE_NAME
+ "(country_name, country_price) VALUES('" + countryName
+ "', '" + countryPrice + "')");
}
Incrementing a value to a specific cell is not available in sqlite. You have to read the current value of cell and add your needed value to it and replace it with the old one. You can use update method.
public void update(String countryName, String price, long id) {
ContentValues cv = new ContentValues();
cv.put(dbHelper.COLUMN_1, countryName); // These Fields should be your
// String values of actual column
// names
cv.put(dbHelper.COLUMN_2, price);
database.update(dbHelper.TABLE_NAME, cv, "_id " + "=" + id, null);
}
every time you're going to add a row to your table you have to read all it and check if the row exists.here is a method to retrieve all rows:
public List<TableRow> getAllRows() {
List<TableRow> rows= new ArrayList<TableRow>();
Cursor cursor = database.query(Helper.TABLE_SITUPS, allColumns,
null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
TableRow row = cursorToRow(cursor);
comments.add(row);
cursor.moveToNext();
}
// Make sure to close the cursor
cursor.close();
return rows;
}
TableRow is a class for database table rows and contains fields stands for actual table columns.
with iterating this list and get "country" value of each one you can understand if that row exists or not.
These are basic concepts of sqlite databases programming. I recommend you to research a bit in this matter.
I don't know your database class, but check this method:
return this.sqliteDBInstance.insertWithOnConflict(DB_TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE);
If you are creating your column correctly, if there is a conflict, the new entry will replace the old one.
EDIT: after your last comment, all you need is an update: first query your database with the name of your item (check carefully if parameters are ok):
return this.sqliteDBInstance.query(DB_TABLE_NAME, null, DB_COLUMN_1_NAME + "=?", new String[] {productName}, null, null, null);
This will return a Cursor with 0 or 1 row. If there aren't row, you can proceed inserting data normally (don't forget to add your counter: is 1 on first insert):
public void insertCountry(String countryName, String countryPrice) {
sqliteDBInstance.execSQL("INSERT INTO " + DB_TABLE_NAME
+ "(country_name, country_price) VALUES('" + countryName
+ "', '" + countryPrice + "', '" + countryCounter + "')");
}
if there is 1 row, your product is already on your database, so just iterate the Cursor, take the value on counter, add +1 on it and update your database with this method:
public int update (String table, ContentValues values, String whereClause, String[] whereArgs)
I'm setting up an SQLite Database and I've got most things set up how I think they're supposed to be. The main error has to with a column not being where it should be. I initialized the database column names in strings like so:
public static final String KEY_ROWID = "_id";
public static final String KEY_SPORT = "given_sport";
public static final String KEY_NAME = "given_name";
public static final String KEY_DATE = "given_date";
public static final String KEY_TIME = "given_time";
public static final String KEY_PERIOD = "given_period";
public static final String KEY_LOCATION = "given_location";
When it was time to create a table with the column names:
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
KEY_SPORT + " TEXT NOT NULL, " +
KEY_NAME + " TEXT NOT NULL, " +
KEY_DATE + " TEXT NOT NULL, " +
KEY_TIME + " TEXT NOT NULL, " +
KEY_PERIOD + " TEXT NOT NULL, " +
KEY_LOCATION + "TEXT NOT NULL);"
);
The problem now is that I'm getting the following error:
05-27 04:13:01.448: E/Database(273): android.database.sqlite.SQLiteException: table groupTable has no column named given_location: , while compiling: INSERT INTO groupTable(given_location, given_time, given_date, given_period, given_sport, given_name) VALUES(?, ?, ?, ?, ?, ?);
It seems like the table names are being reordered and that's what is causing the error in insertion. I'm clueless though and I'd really appreciate some help with this.
EDIT: here's the INSERT command
ContentValues cv = new ContentValues();
cv.put(KEY_SPORT, sportInput);
cv.put(KEY_NAME, nameInput);
cv.put(KEY_DATE, dateInput);
cv.put(KEY_TIME, timeInput);
cv.put(KEY_PERIOD, periodInput);
cv.put(KEY_LOCATION, locationInput);
return dbSQL.insert(DATABASE_TABLE, null, cv);
The problem is probably that you've changed the database structure but not the database version. It's a weird issue that I had to spend a lot of time figuring out the first time.
In your DatabaseHelper class there should be a version number, just increment it by one anytime you change any table schema etc.
EDIT
You're missing a space before the "TEXT" in your SQL table creation.
It should be:
...
+ KEY_LOCATION+ " TEXT" ...
once you fix that, increment the version number again.
The order of the table columns will not create "no column" error. If you have added the column to your table after running your app at least once but haven't incremented the database version, this is one way to cause this error.
The order of these columns:
INSERT INTO groupTable(given_location, given_time, given_date, given_period, given_sport, given_name) ...
depends on the order of the columns when you write your INSERT statement, it is not a fixed order based off of the CREATE command.