I have a problem to create a table. If I try to get a value from the second column, android writes a empty space in the toast. But if I try to get a value from the first column, android writes the value of the column correctly. The query functions to write the first column and to write the second column are equal. So I think the Creation of the Table is the problem. But look yourself:
public SQLiteDatabase tabelleerstellen(){
SQLiteDatabase leveldatabase = openOrCreateDatabase("leveldata.db",SQLiteDatabase.CREATE_IF_NECESSARY, null);
leveldatabase.setVersion(1);
final String CREATE_TABLE_LEVEL =
"CREATE TABLE IF NOT EXISTS tbl_level ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "ME1 TEXT, "
+ "ME2 TEXT, "
+ "ME3 TEXT, "
+ "ME4 TEXT, "
+ "ME5 TEXT, "
+ "ME6 TEXT, "
+ "ME8 TEXT, "
+ "GESCHAFFT INTEGER);";
leveldatabase.execSQL(CREATE_TABLE_LEVEL);
return leveldatabase;
}
public void tester(SQLiteDatabase leveldata){
ContentValues cursortester = new ContentValues();
cursortester.put("ME2","25");
leveldata.insert("tbl_level",null,cursortester);
String[] testerpr = {"ME2"};
Cursor testerprüfen = leveldata.query("tbl_level",testerpr,null,null, null, null,null,null);
testerprüfen.moveToFirst();
String dada = testerprüfen.getString(testerprüfen.getColumnIndex("ME2"));
Toast testertoast = Toast.makeText(getApplicationContext(),dada,Toast.LENGTH_SHORT);
testertoast.show();
}
Please check the following things:
Please make sure the table is up to date .. so try to call DROP TABLE IF EXISTS tbl_level; and recreate the table.
If you run a test make sure the table is completely empty ... so delete everything at the beggining of the test.
If the table can contain elements during the test then make sure you check the last inserted element. Please note that calling testerprüfen.moveToFirst(); moves the cursor to the first row in the table so checking that row every time is even if the table contains 50 elements is not a good thing. In this case you either use a sorting option in your query of uese while (testerprüfen != null && testerprüfen.moveToNext()) {// Your code here}
All in all I think your problem is that you already inserted more that one element in the able but you always check only the first element (with testerprüfen.moveToFirst();). Please not that there is a cursor.moveToLast() method that you can also call. This method moves the cursor to the last row in the table.
Related
I have an app that allows the user to save some chosen rows from a temporary table. The user is able to name the new table.
I am successfully creating a table using the name the user has input, and putting all the chosen rows from the temporary table into the new table.
However, if the table name they enter already exists, I want to notify them via Toast and have them choose another name. I am still learning sqlite - is there a way to do this?
In my head I am using some sort of if statement to check if the table exists, and then executing code, however half of it is in sqlite and half is in java. I'm not sure the correct way to do this. Any suggestions are greatly appreciated!
private void createTable() {
dbHandler.getWritableDatabase().execSQL("CREATE TABLE IF NOT EXISTS " + favoriteName + " ( _id INTEGER PRIMARY KEY AUTOINCREMENT , exercise TEXT , bodypart TEXT , equip TEXT );");
dbHandler.getWritableDatabase().execSQL("INSERT INTO " + favoriteName + " SELECT * FROM randomlypicked");
Try
Cursor cursor = dbHandler.getReadableDatabase().rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '"+tableName +"'", null);
if(cursor!=null) {
if(cursor.getCount()>0) { //table already exists
//show toast
cursor.close();
return;
}
cursor.close();
}
//create table and insert normally
I am developing an android app where I want to delete the last row in one of my database table. I have tried the code below, but its throwing a syntax error.
public void deletelatestprofilefromsystemsettings()
{
String maxid = System_id + "="+"SELECT MAX ("+System_id+") FROM" +TABLE_SYSTEM_SETTINGS;
getWritableDatabase().delete(TABLE_SYSTEM_SETTINGS, maxid ,null);
}
Please help! Thanks!
You are lacking a space after the FROM, and subqueries must be written in parentheses:
String maxid = System_id + "=" +
"(SELECT MAX("+System_id+") FROM " + TABLE_SYSTEM_SETTINGS + ")";
You are trying to execute a DELETE with a SELECT in the same query. AFAIK you shouldn't do it. You have to execute the SELECT query first, in order to retrieve the desired id, then execute the deletion. In other words, execute Cursor c = getWritableDatabase().query(), read the id from the cursor, then use it in getWritableDatabase().delete().
Also, add a space after ") FROM", so it becomes ") FROM " in order to avoid a syntax error.
This is my database
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
KEY_CATEGORY + " TEXT NOT NULL, " +
KEY_DATE + " TEXT, " +
KEY_PRICE + " LONG, " +
KEY_DETAILS + " TEXT NOT NULL);"
);
and this is the method for deleting all data
public void deleteall() {
// TODO Auto-generated method stub
ourDatabase.delete(DATABASE_TABLE, null, null);
}
and this is the method for deleting a particular data
public void deletentry(long l) {
// TODO Auto-generated method stub
ourDatabase.delete(DATABASE_TABLE, KEY_ROWID + " = " + l,null);
}
Here using the data I deleted but incremented row-id remains there, which I want to reset to 1 as the data is deleted also if I delete a particular data the row-id changes it's value in a sequence manner there should be no gap in between row-id.
I don't think autoincrement is your best option. If your goal is to create a simple numbered table with no gaps, it may be much easier to handle this using a table with a column for you to manually keep up with your ID's.
If you created a table like that, you could then write helper methods in your code for the following operations: addColumn, removeColumn, emptyTable.
Your addColumn method would query the table and determine the max(ID) then add 1 and use that number for the next entry.
Your removeColumn method could remove the entry by ID, then use that ID to resequence everything above it. Or, if order is not important, it could take the last row and re-id it to fill in the gap.
Your emptyTable method could remove all entries.
Update
Maybe this can get you started. The methods would need to be defined in your program. You would have to put the code inside them and then set them up to be called.
For example:
public void addColumn(String category, long date, String details) {
//code here would need to determine the max of ID and add one
//to it. the sql below would retrieve max, i dont know the sql lite code
//off the top of my head.
//SELECT MAX(ID) FROM DATABASE_TABLE;
int newID = max + 1;
//add row to the database using newID
}
public void removeColumn(int id) {
//remove column from database
//DELETE FROM DATABASE_TABLE WHERE ID = id;
//change last entry to use id
//UPDATE DATABASE_TABLE SET ID = id WHERE id = (SELECT MAX(ID) FROM DATABASE_TABLE);
}
public void emptyTable() {
//DELETE FROM DATABASE_TABLE;
}
To call these methods, you would call them like any other java method in your class:
addColumn(12, 'text', (long)100, 'text');
removeColumn(10);
emptyTable();
SQLite keeps the largest ROWID in the special SQLITE_SEQUENCE table. You can delete that table as:
db.delete("SQLITE_SEQUENCE","NAME = ?",new String[]{TABLE_NAME});
Unfortunately, SQLite AUTOINCREMENT is not guaranteed to work as you want. Quoting the docs:
If no ROWID is specified on the insert, or if the specified ROWID has
a value of NULL, then an appropriate ROWID is created automatically.
The usual algorithm is to give the newly created row a ROWID that is
one larger than the largest ROWID in the table prior to the insert. If
the table is initially empty, then a ROWID of 1 is used. If the
largest ROWID is equal to the largest possible integer
(9223372036854775807) then the database engine starts picking positive
candidate ROWIDs at random until it finds one that is not previously
used. If no unused ROWID can be found after a reasonable number of
attempts, the insert operation fails with an SQLITE_FULL error. If no
negative ROWID values are inserted explicitly, then automatically
generated ROWID values will always be greater than zero.
If you need this specific behaviour you described, the only solution would be for you to manually control the KEY_ROWID for your table, making sure you properly account for inserts and deletes.
You can also delete your table from SQLite_Sequence using
sqlDb.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = 'YOUR_TABLE_NAME'");
I am applying a batch of ContentProviderOperations on my provider:
ContentProviderResult[] result = resolver.applyBatch(...)
Everything works as expected the data is being inserted into the DB, but if I want to extract the id(s) the last element of the uri which should be the id is always null.
Is this happening because I have set the _id of the table to autoincrement (in other words would it work if I am not autoincrementing the id and fill it with a manually uid from my code).
If not, can anyone tell me whats causing this behavior.
Update: This is the String for creating the table:
private static final String CREATE_TABLE_WORKFLOWSTATES =
"CREATE TABLE " + Tables.WORKFLOWSTATES + " ("
+ BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ WorkflowStatesColumns.NAME + " TEXT NOT NULL,"
+ "UNIQUE ("+ WorkflowStatesColumns.NAME + ") ON CONFLICT IGNORE)";
and if i view the table I can see the columns _id and name, the inserted data that is visible shows that the autoincrement works properly.
Update 2: This is how I have build the ContentProviderOperation:
this is my ArrayList with ContentProviderOperations (CollectionUtils is a custom class in order to instantiate the Arraylist):
ArrayList<ContentProviderOperation> batch = CollectionUtils.newArrayList();
and this is the actual operation:
batch.add(ContentProviderOperation
.newInsert(InvoiceContract.addCallerIsSyncAdapterParameter(WorkflowStates.CONTENT_URI))
.withValue(WorkflowStates.NAME, task.getWFS()).build());
In case of insertion (and I guess that you insert a row into your database), the result[i].uri contains URI of a newly inserted row, where i is the index of the corresponding operation in operations array. Try to print this URI and you'll see if it corresponds to real id.
If one of your operation is UPDATE or DELETE the corresponding result URI will be null, but result[i].count will contain the number of updated/deleted rows.
UPDATE
I guess the problem is that you have a unique index on NAME. Maybe, you have a row already inserted with the same name?
UPDATE2
The problem was that the insert function in the ContentProvider did not return the id correctly.
I have a database that is being filled by user defined EditTexts. None of the edit texts should allow empty fields. I know that I can check for this with a couple simple if-statements: if myEditText.getText().toString().equals("") // display error. However I would perfer to use this opportunity to brush up on my SQLite and error catching (as demonstrated in my add method). How would I go about altering the columns in the table below to NOT NULL and generating/catching an error when a user attempts to add/update with empty fields?
My database table:
db.execSQL("CREATE TABLE inventory (category TEXT, itemNum TEXT, quantity INTEGER, price REAL, image INTEGER, UNIQUE(category, itemNum) ON CONFLICT FAIL);");
My add method:
... fill ContentValues values
try{
db.getWritableDatabase().insertWithOnConflict(DatabaseHelper.TABLE_NAME, DatabaseHelper.CATEGORY, values, SQLiteDatabase.CONFLICT_FAIL);
fillItemNumbers();
}
catch(SQLiteConstraintException e)
{
Toast
.makeText(MyActivity.this, etItemNum.getText().toString() + " already exists in " + catSpinner.getSelectedItem().toString() +". Consider using Update.",Toast.LENGTH_LONG)
.show();
}
My update method:
... fill ContentValues values
String[] args = {catSpinner.getSelectedItem().toString(), etItemNum.getText().toString()};
int rowsAffected = db.getWritableDatabase().update(DatabaseHelper.TABLE_NAME, values, DatabaseHelper.CATEGORY + "=? AND " + DatabaseHelper.ITEM_NUMBER + "=?" , args);
UPDATE:
I did a little digging and came up with this:
db.execSQL("CREATE TABLE inventory (category TEXT NOT NULL, itemNum TEXT NOT NULL, quantity INTEGER NOT NULL, price REAL NOT NULL, image INTEGER NOT NULL, UNIQUE(category, itemNum) ON CONFLICT FAIL);");
Is this what I am looking for? If so, how can I use this to my advantage (see above)?
I am not sure if you can actually Alter Column Definition for table. I know you can Alter Table itself, like adding new Column to Table. You might need little trick to modify your database if there is lot of data in it that you want to preserve.
One way to it to create new table and try copying data to new table and afterwards remove old table and rename new Table. It's not most efficient way to do it but it'll get the job done though.
http://www.sqlite.org/lang_altertable.html
EDIT
Here you go
CREATE TABLE inventory (category TEXT not null, itemNum TEXT not null, quantity INTEGER not null, price REAL not null, image INTEGER not null, UNIQUE(category, itemNum) ON CONFLICT FAIL);
EDIT 2
Try this
CREATE TABLE inventory (category TEXT not null ON CONFLICT FAIL, itemNum TEXT not null ON CONFLICT FAIL, quantity INTEGER not null ON CONFLICT FAIL, price REAL not null ON CONFLICT FAIL, image INTEGER not null ON CONFLICT FAIL, UNIQUE(category, itemNum) ON CONFLICT FAIL);
All you need to do is set the columns to NOT NULL.
Then use
insertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm)
and
updateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm)`
There are several constants you can use for the conflictAlgorithm, depending on exactly what you want to happen. If you want to simply not enter the data into the table, CONFLICT_IGNORE will do the trick. If you want a return code letting you know so you can act on it (let the user know) then you might want CONFLICT_FAIL.
See this for further information.
Hope this helps.