The database is created using a SQLiteOpenHelper:
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String SQL_CREATE_INVENTORY_TABLE = "CREATE TABLE " + InventoryEntry.TABLE_NAME + "("
+ InventoryEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ InventoryEntry.COLUMN_PRODUCT_IMAGE + " BLOB, "
+ InventoryEntry.COLUMN_PRODUCT_NAME + " TEXT NOT NULL, "
+ InventoryEntry.COLUMN_PRODUCT_PRICE + " REAL NOT NULL, "
+ InventoryEntry.COLUMN_PRODUCT_QUANTITY + " INTEGER, "
+ InventoryEntry.COLUMN_PRODUCT_DESCRIPTION + " TEXT);";
sqLiteDatabase.execSQL(SQL_CREATE_INVENTORY_TABLE);
}
All the constants are defined in a contract, this is the COLUMN_PRODUCT_IMAGE one:
public static final String COLUMN_PRODUCT_IMAGE = "image";
In a CursorAdapter, I try to access the image column from the bindView method, after adding some random data to the database:
#Override
public void bindView(View view, final Context context, Cursor cursor) {
ImageView imageView = view.findViewById(R.id.product_image);
byte [] bytes = cursor.getBlob(cursor.getColumnIndexOrThrow(InventoryEntry.COLUMN_PRODUCT_IMAGE));
Bitmap bitmap = BitmapUtils.getBitmap(bytes);
imageView.setImageBitmap(bitmap);
}
This produces an java.lang.IllegalArgumentException: column 'image' does not exist
I double checked the database using windows cmd, here's how it looks:
sqlite> select * from inventory;
_id image name price quantity description
---------- ---------- ---------- ---------- ---------- -----------
1 ff 5.0 5 fds
Column 'image' exists, so why the error?
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 update data in rows in my DB, but i catch error that there's no such column (no such column 'Moscow' or another)
This is DBHelper code:
public static final String tableName = "currentWeather";
public static final String KEY_ID = "_id";
public static final String cityName = "city";
public static final String cityTemp = "temperature";
And creating DB:
sqLiteDatabase.execSQL("create table " + tableName + "(" + KEY_ID + "
integer primary key autoincrement,"
+ cityName + " text," + cityTemp + " text, " + " UNIQUE(" + cityName +
"))");
and error shows when i try to execSQl in response:
sqLiteDatabase.execSQL(
"UPDATE " + DBHelper.tableName + " SET " +
DBHelper.cityTemp + "=" +
response.body().getForecastMain().getTemp() + "
WHERE "
+ DBHelper.cityName + "=" + cityName);
I expect to update temperature data in rows by cityName
cityName and response.body().getForecastMain().getTemp() are strings and they should be passed surrounded with single quotes to the sql statement:
sqLiteDatabase.execSQL(
"UPDATE " + DBHelper.tableName + " SET " + DBHelper.cityTemp + "='" + response.body().getForecastMain().getTemp() + "'" +
"WHERE " + DBHelper.cityName + " = '" + cityName + "'"
);
But the recommended and safe way of doing the update is with the use of ContentValues and ? as placeholders for the parameters:
ContentValues cv = new ContentValues();
cv.put(DBHelper.cityTemp, String.valueOf(response.body().getForecastMain().getTemp()));
int rows = sqLiteDatabase.update(
DBHelper.tableName,
cv,
DBHelper.cityName + " = ?",
new String[] {cityName}
);
You can examine the value of the integer variable rows.
If it is 1 this means that 1 row was updated (because cityName is unique) so the update was successful.
I think you have changed column name or add new one (city). So you can fix it by two ways
By uninstall the application from phone
Add column name in upgrade method.
Example:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// If you need to add a column
if (newVersion > oldVersion) {
db.execSQL("ALTER TABLE foo ADD COLUMN new_column INTEGER DEFAULT 0");
}
}
The thing is you need to wrap the values after the = sign in single quotations in the UPDATE statement. As for digits they work in both cases.
For example here is the correct syntax
UPDATE currentWeather
SET temperature = 45
WHERE
city = 'Moscow'
But in your code I'm assuming cityName has the value Moscow without the single quotation marks so the converted SQL code will be like this
UPDATE currentWeather
SET temperature = 45
WHERE
city = Moscow
Now the sql interpreter will think Moscow is some database object or column or something and not a literal value. So you need to surround your values in single quotation marks.
Also consider What the data type of response.body().getForecastMain().getTemp() is.
If it's int you have to parse it or something, as the data type of the related column is Text.
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.
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
So i am trying to insert some data in the internal sqlite database but after i run the insert no data has been added. There are, as far as i can see no errors in the logs and every debug log i put into it is shown. If i try to run the query that is returned in the log in sqlitestudio it works without a problem so i haven't got a clue as to what is going wrong.
#Override
public void onCreate(SQLiteDatabase db) {
String SQL = pictureTable();
db.execSQL(SQL);
}
private String pictureTable() {
return "CREATE TABLE geophoto_db_pictures ( picid integer,"
+ "name varying character(50),"
+ "city varying character(20) NOT NULL,"
+ "zipcode varying character(20) NOT NULL,"
+ "country varying character(20) NOT NULL,"
+ "picdate datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ "tags varying character(200),"
+ "image varying character(200) NOT NULL,"
+ "uploaded integer NOT NULL DEFAULT 0, PRIMARY KEY (picid))";
}
#Override
public void savePicture(Picture pic) {
Log.d(LOG_TAG, "saving picture started. Data: " + pic.getName());
// clean the inputs
String name = pic.getName();
String city = pic.getCity();
if (city != null) {
city = "'" + city + "'";
}
String country = pic.getCountry();
if (country != null) {
country = "'" + country + "'";
}
String zip = pic.getZipcode();
if (zip != null) {
zip = "'" + zip + "'";
}
String tags = tagsToString(pic.getTags());
String image = pic.getImage();
// Insert Query, all possible null values on "not null" rows will be
// replaced by a default value.
String SQL = "INSERT INTO geophoto_db_pictures(name, city, zipcode, country, tags, image)"
+ "VALUES('"
+ name
+ "',"
+ "IFNULL("
+ city
+ ", 'Unknown')"
+ ","
+ "IFNULL("
+ zip
+ ", 'Unknown')"
+ ","
+ "IFNULL("
+ country + ",'Unknown')" + ",'" + tags + "','" + image + "')";
Log.d(LOG_TAG, SQL);
executeWriteQuery(SQL);
ArrayList<Picture> list = getAllPictures();
Log.d(LOG_TAG, "Size :"+list.size());
}
private Cursor executeWriteQuery(String query){
Log.d(LOG_TAG, "execute write query");
SQLiteDatabase db = getWritableDatabase();
Cursor response = db.rawQuery(query, null);
Log.d(LOG_TAG, "write query executed");
return response;
}
All tips/help greatly appreciated!
Thomas
Try to put a semicolon at the end of table creation query. In your case as show below
private String pictureTable() {
return "CREATE TABLE geophoto_db_pictures ( picid integer,"
+ "name varying character(50),"
+ "city varying character(20) NOT NULL,"
+ "zipcode varying character(20) NOT NULL,"
+ "country varying character(20) NOT NULL,"
+ "picdate datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ "tags varying character(200),"
+ "image varying character(200) NOT NULL,"
+ "uploaded integer NOT NULL DEFAULT 0, PRIMARY KEY (picid));";
}
While providing a query through an external String, you will need to provide SQL query with an end of statement ;. Using the primitive SQLite does not require ; as it just takes arguments and create function query itself. I have experienced both cases and I ended up understanding the way I have put it here.
The problem you are facing is that you are trying to use rawQuery() to insert a record, when you should be using execSQL() instead (see this answer).
So, the correct code for executeWriteQuery would be as follows:
private void executeWrite(String command){
Log.d(LOG_TAG, "execute write");
SQLiteDatabase db = getWritableDatabase();
db.execSQL(command);
Log.d(LOG_TAG, "write executed");
}
Also, consider using insert() instead as that will allow you to get a return value to determine whether or not the data was inserted successfully.