After delete from sqlite DB have blank row, and the next data record to the next row after empty. How to fix this problem? Before i delete some thin all works correctly, but after deleting i have this problem.
private static final String DB_CREATE =
"create table " + DB_TABLE + "(" +
COLUMN_ID + " integer primary key autoincrement, " +
COLUMN_NAME + " text, " +
COLUMN_TIME + " text, " +
COLUMN_RAW_TIME + " integer " +
");";
for deleting i use:
//method which called delRec from DB class
public boolean onContextItemSelected(MenuItem item) {
if (item.getItemId() == CM_DELETE_ID) {
AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) item
.getMenuInfo();
db.delRec(acmi.id);
getSupportLoaderManager().getLoader(0).forceLoad();
}
else if (item.getItemId() == RESET_STOPWATCH){
AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) item
.getMenuInfo();
db.resetTime(Long.toString(acmi.id));
getSupportLoaderManager().getLoader(0).forceLoad();
}
return super.onContextItemSelected(item);
}
// delete
public void delRec(long id) {
//mDB.delete(DB_TABLE, COLUMN_ID + " = " + id, null);
mDB.execSQL("DELETE FROM mytab WHERE _id = " + id);
}
for adding:
public void addRec(String txt, String txt2, long time) {
ContentValues cv = new ContentValues();
cv.put(COLUMN_TIME, txt2);
cv.put(COLUMN_NAME, txt );
cv.put(COLUMN_RAW_TIME, time );
mDB.insert(DB_TABLE, null, cv);
The autoincrement makes the generated row ids unique. The same id won't be generated again.
If you want to generate ids as MAX(id)+1 with possible id reuse, remove the autoincrement and keep the primary key. If you want to reuse any available id number in the middle, you'll have to find it first.
Other than that, reconsider your approach. Missing id numbers in the middle should not be a problem. The problem is in the code where you display your data, not in the data itself.
Related
I've been trying for some days to load some data from a SQLite database into a ListView inside a Fragment but I'm having this issue that I can't see the solution neither found help online.
My database consists of two tables, 'user' and 'team', being the former in a one to many relation with the later.
//User Table
public static final String CREATE_TABLE_USER =
"CREATE TABLE " + USER_TABLE + "("
+ USER_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ USER_NAME + " TEXT NOT NULL,"
+ USER_SURNAME + " TEXT NOT NULL,"
+ USER_EMAIL + " TEXT NOT NULL,"
+ USER_PHONE + " NUMBER,"
+ USER_PASSWORD + " TEXT NOT NULL)";
//Team Table
public static final String CREATE_TABLE_TEAM =
"CREATE TABLE " + TeamColumns.TEAM_TABLE + "("
+ TeamColumns.TEAM_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ TeamColumns.TEAM_NAME + " TEXT NOT NULL,"
+ TeamColumns.TEAM_COUNTRY + " TEXT NOT NULL,"
+ TeamColumns.TEAM_BOSS + " TEXT NOT NULL,"
+ TeamColumns.TEAM_DRIVER1 + " TEXT NOT NULL,"
+ TeamColumns.TEAM_DRIVER2 + " TEXT NOT NULL,"
+ TeamColumns.TEAM_CAR + " TEXT NOT NULL,"
+ TeamColumns.TEAM_POINTS + " NUMBER,"
+ TeamColumns.TEAM_ICON + " TEXT,"
+ TeamColumns.TEAM_USER_ID + " INTEGER,"
+ "CONSTRAINT userID_FK FOREIGN KEY (userID) REFERENCES " + USER_TABLE + "(id))";
So with a database structured this way, I want the ListView to only show the teams associated to the one user logged in. But i can't find how to do it, I don't really select what SQL query is used when loading info, trying to alter the cursor in the overriden bindView method does nothing and the furthest i managed to get showed the wanted rows, but the app crushed the moment i scrolled down to the bottom (I presume i just created a bunch of empty list items where usually are more items). Online search has also been of no help (sorry in advance if this question is already here) so I'm at a stalemate with this part of my app.
My question is:
Is there a way to change the SQL sentence my CustomCursorAdapter uses to load my data?
This is where I load all the data into the ListItem in the CursorAdapter class:
#Override
public void bindView(View view, final Context context, Cursor cursor) {
//Team info placeholders
final ImageView logoView = view.findViewById(R.id.listIcon);
TextView nameText = view.findViewById(R.id.listName);
TextView countryText = view.findViewById(R.id.listCountry);
TextView directorText = view.findViewById(R.id.listDirector);
//Retrieving info
String logoURI = cursor.getString(cursor.getColumnIndexOrThrow(TeamContract.TeamColumns.TEAM_ICON));
String name = cursor.getString(cursor.getColumnIndexOrThrow(TeamContract.TeamColumns.TEAM_NAME));
String country = cursor.getString(cursor.getColumnIndexOrThrow(TeamContract.TeamColumns.TEAM_COUNTRY));
String director = cursor.getString(cursor.getColumnIndexOrThrow(TeamContract.TeamColumns.TEAM_BOSS));
//Seting the image
Glide.with(context).asBitmap()
.load(Uri.parse("file:///android_asset/" + logoURI))
.error(R.drawable.ic_baseline_error_outline_24).centerCrop().into(new BitmapImageViewTarget(logoView) {
#Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(), resource);
drawable.setCircular(true);
logoView.setImageDrawable(drawable);
}
});
//Setting the texts
nameText.setText(name);
countryText.setText(country);
directorText.setText(director);
}
And here where I initialize the Adapter from my Fragment class:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_team, container, false);
// Referencias UI
teamList = root.findViewById(R.id.teams_list);
mteamAdapter = new TeamAdapter(getActivity(), null);
// Setup
teamList.setAdapter(mteamAdapter);
// Eventos
teamList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Cursor currentItem = (Cursor) mteamAdapter.getItem(i);
String currentTeamId = currentItem.getString(currentItem.getColumnIndexOrThrow(TeamContract.TeamColumns.TEAM_ID));
launchTeamView(currentTeamId);
}
});
mTeamDbHelper = new DatabaseHelper(getActivity());
loadLawyers();
return root;
}
I'm trying to remove a row from an SQL table using this code below. However, whenever I call this method I get this following error:
android.database.sqlite.SQLiteException: no such column: Plumber (code 1): , while compiling: DELETE FROM service WHERE name = Plumber
public boolean deleteService(String name){
SQLiteDatabase db = this.getWritableDatabase();
boolean result = false;
String query = "SELECT * FROM "
+ TABLE_SERVICE
+ " WHERE "
+ COLUMN_NAME
+ " = \""
+ name
+ "\""
;
Cursor cursor = db.rawQuery(query, null);
if(cursor.moveToFirst()){
String nameStr = cursor.getString(0);
db.delete(TABLE_SERVICE, COLUMN_NAME + " = " + nameStr, null);
cursor.close();
result = true;
}
db.close();
return result;
}
This is my table
public void onCreate(SQLiteDatabase db){
String CREATE_USERS_TABLE = "CREATE TABLE " +
TABLE_SERVICE + "("
+
COLUMN_NAME + " TEXT," +
COLUMN_RATE + " TEXT," +
COLUMN_CATEGORY + " TEXT," + COLUMN_SUBCATEGORY + " TEXT)";
db.execSQL(CREATE_USERS_TABLE);
}
First you're fetching all the rows that in COLUMN_NAME have the value name.
Next you want to delete the 1st of these rows (maybe it's the only one?) because nameStr gets the value of the 1st column which is COLUMN_NAME.
Why are you doing this?
Just execute this statement:
int number = db.delete(TABLE_SERVICE, COLUMN_NAME + " = '" + name + "'", null);
if number gets the value 0 then no rows were deleted, else it gets the number of deleted rows.
delete deletes rows not columns.
If you want to get rid of a column, you need to drop it. The SQL syntax is:
alter table table_service drop column <column_name>;
I don't know how to express this in java with the methods that you are using.
Ensure that your SQL syntax is correct, and that "Plumber" is a string with double quotes. By my experience, these errors are usually caused by an incorrect column or name.
Use this format:
DELETE FROM table_name WHERE condition(s)
SQLite browser can also help you visualize your database.
I am brand new to multiple tables in an SQLite database and am trying to find out what the best practices are for inserting values into multiple tables. My main question is do I need to Create another ContentValues object for inserting the values into a second table? I am really stumped on how to perform the insert(). Here is what I am trying so far.
Here are the two tables and schema
/* Creating a common attributes table here. */
private static final String CREATE_COMMON_ATTRIBUTES_TABLE = "create table "
+ COMMON_ATTRIBUTES_TABLE + "(" + DBColCons.UID_COMMON_ATTRIBUTES + " integer" +
" primary key autoincrement, " + DBColCons.GPS_POINT+ " integer not null, "
+ DBColCons.EXISTING_GRADE_GPS_POINT+ " integer not null, "
+ DBColCons.COVER+ " real not null, "+ DBColCons.NOTES+ " text, "
+ DBColCons.DATE+ " text)";
/* Creating a weld table here */
private static final String CREATE_WELD_TABLE = " create table " +WELD_TABLE+ "("
+ DBColCons.UID_WELD + " integer primary key, " + DBColCons.WELD_TYPE +
" text, " + DBColCons.WELD_ID + " text, " + DBColCons.DOWNSTREAM_JOINT +
" text, " + DBColCons.UPSTREAM_JOINT + " text, " + DBColCons.HEAT_AHEAD +
" text, " + DBColCons.LENGTH_AHEAD + " real, " + DBColCons.WALL_CHANGE +
" text, " + DBColCons.WELD_WALL_THICKNESS + " text, "
+ DBColCons.WELDER_INITIALS + " text, foreign key("+DBColCons.WELD_ID+") references" +
"("+DBColCons.GPS_POINT+"))";
Here is the method I am wanting to use for the insert() with some class getters() for the Weld class, which I am passing in as a parameter.
public boolean insertWeld(Weld weld) {
/* Get a writable copy of the database */
SQLiteDatabase db = this.getWritableDatabase();
/* Content values to insert with Weld class setters */
ContentValues contentValuesWeld = new ContentValues();
try {
contentValuesWeld.put(DBColCons.GPS_POINT, weld.getGpsPoint());
contentValuesWeld.put(DBColCons.WELD_TYPE, weld.getWeldType());
contentValuesWeld.put(DBColCons.WELD_ID, weld.getWeldId());
contentValuesWeld.put(DBColCons.DOWNSTREAM_JOINT, weld.getDownstreamJoint());
contentValuesWeld.put(DBColCons.UPSTREAM_JOINT, weld.getUpstreamJoint());
contentValuesWeld.put(DBColCons.HEAT_AHEAD, weld.getHeatAhead());
contentValuesWeld.put(DBColCons.LENGTH_AHEAD, weld.getLengthAhead());
contentValuesWeld.put(DBColCons.EXISTING_GRADE_GPS_POINT, weld.getExistingGradePoint());
contentValuesWeld.put(DBColCons.COVER, weld.getCover());
contentValuesWeld.put(DBColCons.WALL_CHANGE, weld.getWallChange());
contentValuesWeld.put(DBColCons.WELD_WALL_THICKNESS, weld.getWeldWallThickness());
contentValuesWeld.put(DBColCons.WELDER_INITIALS, weld.getWelderInitials());
contentValuesWeld.put(DBColCons.NOTES, weld.getNotes());
/* adding the date in here to the row. */
contentValuesWeld.put(DBColCons.DATE, String.valueOf(mStrDate));
/* Inserting into the weld table */
db.insertWithOnConflict(WELD_TABLE, DBColCons.WELDER_INITIALS, contentValuesWeld,
SQLiteDatabase.CONFLICT_NONE);
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
The values for DBColCons.GPS_POINT,DBColCons.EXISTING_GRADE_GPS_POINT,DBColCons.GPS_COVER and DBColCons.NOTES are what I want to insert into the Common_Attributes_Table. This is where I am really confused. Do I need to create a separate ContentValues object for those specific values and insert them into the desired table with a separate db.insert() method along with the one I am already using with the insert on the WELD_TABLE?
Help I am lost in this train wreck. Ha.
Thank you all.
You need to call insert() (or insertWithConflict()) for each table you are inserting values into. Unless the values are the same, this implies you will need another ContentValues per table.
If you intend for these inserts to be committed as a single atomic operation, consider using a transaction.
SQLiteDatabase db = ...;
db.beginTransaction();
try {
// do your inserts/etc. here
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
I am working on an android application that uses two databases. Recently, I had to add a new column to one of the databases. Upon doing so, it broke my database. Installing and re-installing the application on my device did nothing, and I also updated the DB version.
Trying to insert data will net me this error:
E/SQLiteLog﹕ (1) table message_table has no column named msg_type
So, I tried taking out the "msg_type" column from the insert, and inserting data which gave me this error:
E/SQLiteLog﹕ (1299) abort at 8 in [INSERT INTO message_table(recipient,message) VALUES (?,?)]: NOT NULL constraint failed: message_table.msg_typeTEXT
Here is the oncreate:
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
COL_1 + " INTEGER PRIMARY KEY AUTOINCREMENT, " + //msg_id
COL_2 + " TEXT NOT NULL, " + //recipient
COL_3 + " TEXT, " + //message
COL_4 + "TEXT NOT NULL);"); //message type
}
and the insert class:
public boolean addMessage(String recipient, String message, String type){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
//populate message object
contentValues.put(COL_2, recipient);
contentValues.put(COL_3, message);
contentValues.put(COL_4, type);
//insert new message
long result = db.insert(TABLE_NAME, null, contentValues);
//check if operation was successful
if(result == -1)
return false;
else
return true;
}
How can I be getting an error for either case? I thought that it didn't recognize the new column was added from the first error, but it also doesn't like not receiving the data for that column.
The error is happening because there is no space between the column name and the TEXT. So the column name becomes message_table.msg_typeTEXT:
COL_4 + "TEXT NOT NULL);"); //message type
This should fix the error:
COL_4 + " TEXT NOT NULL);"); //message type
Here is my code:
DataBaseAlarm mDbHelper = new DataBaseAlarm(this);
db = mDbHelper.getWritableDatabase();
private static final String SQL_CREATE_ENTRIES="CREATE TABLE IF NOT EXISTS"+TABLE_NAME+" ("+rowid+" INTEGER PRIMARY KEY AUTOINCREMENT, "+Title+TEXT_TYPE+Time+TEXT_TYPE+Date+TEXT_TYPE+Repeat+TEXT_TYPE+Note+" TEXT NOT NULL);";
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
Cursor c = db.query(
"Alarms", // The table to query
cols, // The columns to return
null, // The columns for the WHERE clause
null, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null // The sort order
);
from=new String[]{"title","note","time","date","repeat","_id"};
to=new int[]{R.id.title_row,R.id.note_row,R.id.time_row,R.id.date_row,R.id.repeat_row};
adapterCursor =new SimpleCursorAdapter(MainActivity.this, R.layout.alarm_row, c, from, to);
l_list.setAdapter(adapterCursor);
ContentValues cv = new ContentValues();
cv.put("title",msg);
cv.put("note",note);
cv.put("time",hour+":"+minute);
cv.put("date",month+"/"+day+"/"+year);
cv.put("Repeat","daily");
db.insert("Alarms",null,cv);
and for some reason I'm getting this error:
Caused by: android.database.sqlite.SQLiteException: no such column: id (code 1): , while compiling: SELECT id, title, time, date, repeat, note FROM Alarms
Take a look at your table creation code:
private static final String SQL_CREATE_ENTRIES="CREATE TABLE IF NOT EXISTS"+TABLE_NAME+" ("+rowid+" INTEGER PRIMARY KEY AUTOINCREMENT, "+Title+TEXT_TYPE+Time+TEXT_TYPE+Date+TEXT_TYPE+Repeat+TEXT_TYPE+Note+" TEXT NOT NULL);";
It's a mess, and it's full of errors.
It should be something like:
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME +
" (" + rowid + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
Title + " TEXT, " + Time + " TEXT, " + Date + " TEXT, " +
Repeat + " TEXT, " + Note + " TEXT NOT NULL)";
[EDIT]
Also, this
cv.put("date",month+"/"+day+"/"+year);
is not a valid timeString
This one (assuming that year is a 4 character string and month and day are 2 character strings) is:
cv.put("date", year + "-" + month + "-" + day);
For your reference: http://www.sqlite.org/lang_datefunc.html