What is the standard approach to update a boolean column (i.e. a categorical binary INTEGER value) in a SQL (SQLite) table?
(here binary is intended to mean an INTEGER that takes two values only: 0 and 1, hence the quotes in the question title)
Given a table:
CREATE TABLE types (
id INTEGER NOT NULL PRIMARY KEY,
name TEXT,
enabled INTEGER DEFAULT 1)
And a list of objects which can have an enabled/disabled state and which are represented as two lists:
List<Long> idsEnabled = new ArrayList<>();
List<Long> idsDisabled = new ArrayList<>();
Would this be the correct way to store the enabled state (i.e. 0 or 1)?
SQLiteDatabase db = dbHelper.getWritableDatabase();
// upd: NOT WORKING because rawQuery does NOT work for modifying data,
// must use execSQL
db.rawQuery("UPDATE types set enabled=1 where id in ("
+ TextUtils.join(",", idsEnabled) + ")", null);
db.rawQuery("UPDATE types set enabled=0 where id in ("
+ TextUtils.join(",", idsDisabled) + ")", null);
Is there a better, more efficient, OOTB way to do this? My assumption is that updating each row one by one would be the worst case.
The question is not necessarily android-specific, although if there is some android-specific API for doing this it would be helpful.
The method rawQuery() is not the way to update the table.
It is used to return rows in the form of a Cursor.
In this case you must use execSQL():
if (idsEnabled.size() > 0 || idsDisabled.size() > 0) {
String ids1 = TextUtils.join(",", idsEnabled);
String ids0 = TextUtils.join(",", idsDisabled);
String sql =
"UPDATE types " +
"SET enabled = CASE " +
(idsEnabled.size() > 0 ? "WHEN id IN (" + ids1 + ") THEN 1 " : "") +
(idsDisabled.size() > 0 ? "WHEN id IN (" + ids0 + ") THEN 0 " : "") +
"ELSE enabled " +
"END";
db.execSQL(sql);
}
The above statement uses a CASE expression to determine the value that will update the current value of the column.
If you want to update just a small part of the table then it would be more efficient to include a WHERE clause in the UPDATE statement, so you can omit the ELSE part of the CASE expression:
if (idsEnabled.size() > 0 || idsDisabled.size() > 0) {
String ids1 = TextUtils.join(",", idsEnabled);
String ids0 = TextUtils.join(",", idsDisabled);
String idsAll = "";
if (idsEnabled.size() == 0) idsAll = ids0;
else if (idsDisabled.size() == 0) idsAll = ids1;
else idsAll = ids1 + "," + ids0;
String sql =
"UPDATE types " +
"SET enabled = CASE " +
(idsEnabled.size() > 0 ? "WHEN id IN (" + ids1 + ") THEN 1 " : "") +
(idsDisabled.size() > 0 ? "WHEN id IN (" + ids0 + ") THEN 0 " : " ") +
"END " +
"WHERE id IN (" + idsAll + ")";
db.execSQL(sql);
}
Related
I am gonna to add a LineNo to a table and how can I make it will auto increment by 1?
LineNo is no the primary key so how I make it will will auto increment by 1?
This is what I tried, but no working:
String query_edit = "UPDATE " + TABLE_NAME_INV_DTL + " SET " + COL15_INV_DTL + "= +1 ";
db.execSQL(query_edit);
Try this
String query_edit = "UPDATE " + TABLE_NAME_INV_DTL + " SET " + COL15_INV_DTL + "=" + COL15_INV_DTL + " +1 ";
db.execSQL(query_edit);
i like to change the old one into new and my old sql query its in statement and i like to change into prepared statement . how could i change ?
for example :
*
strSql = "SELECT Id as GroupId, Name,Description FROM Groupcodes WHERE deleteFlag=0 and GroupType = '" + StrGroupType + "' ";
if(strSearchBy.length() > 0 && strSearchText.length() > 0)
{
if(strSearchOption.equalsIgnoreCase("Starts With")) {
strSql += " AND " + strSearchBy + " LIKE '" + strSearchText + "%' ";
}
else if(strSearchOption.equalsIgnoreCase("Contains")){
strSql += " AND " + strSearchBy + " LIKE '%" + strSearchText + "%'" ;
}
}
strSql += " ORDER BY Name ASC";
if( nCounter > 0 ) {
strSql += " LIMIT " + (nCounter - 1) + ", " + nMaxCount;
}
*
once you teach for this example then i will do for upcoming codes .
You do it like this:
PreparedStatement mStatement = getDBTransaction().createPreparedStatement("select * from test_table where user_id = ?", 0);
mStatement.setString(1, "4913");
ResultSet rs = mStatement.executeQuery();
The '?' character parametizes the query and later u set its value using setString. Note in the setstring function the first parameter is indicated by index 1 (not 0 ). Also note u dont need ' ' if your where condition is comparing varchars
My table name is TX_TABLE and the column for insertion is TX_AMOUNT , being 'integer'. The insertion of values say like 1234.56 for 1st row and 12345.67 for 2nd row is correctly taking place for me as I could see it by putting breakpoints.
Now, if I retrieve the data from TX_AMOUNT column the values are shown like
1234.56 for the 1st row which is OK and for the 2nd row it shows as 12345.7
instead of 12345.67. If I enter a value with upto 15 digits without decimals
there is no problem. Only when values with decimals like in 12345.67 it shows
like 12345.7.
I give below my codes:
create table:
private static final String CREATE_TX_TABLE= "CREATE TABLE " + TX_TABLE + " (" +TX_UID+ " INTEGER PRIMARY KEY AUTOINCREMENT," + TX_TITLE_UID + " INTEGER," + TX_AMOUNT + " INTEGER," + TX_PARTICULARS + " VARCHAR(255)," + TX_DATE+" DATE," + TX_ID + " VARCHAR(255)," + TX_NAME + " VARCHAR(255)," + TX_CONTRA + " VARCHAR(255)," + TX_LISTVIEW_DATE + " DATE);";
insertion:
public void insertTxData(String inputparticulars, String inputamount, String showSelectedTitle, String inputID, String txid, String contraYorNo){
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues contentvalues = new ContentValues();
if (inputparticulars.equals("") || inputparticulars.equals(null)){
inputparticulars= "particulars not entered";
}
contentvalues.put(VivzHelper.TX_PARTICULARS,inputparticulars);
// with breakpoint here, the values entered are perfectly getting in
contentvalues.put(VivzHelper.TX_AMOUNT, inputamount);
contentvalues.put(VivzHelper.TX_TITLE_UID, inputID);
contentvalues.put(VivzHelper.TX_ID, MainActivity.txid);
contentvalues.put(VivzHelper.TX_DATE, new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
contentvalues.put(VivzHelper.TX_LISTVIEW_DATE, new SimpleDateFormat("dd-MM-yyyy").format(new Date()));
contentvalues.put(VivzHelper.TX_NAME,showSelectedTitle);
contentvalues.put(VivzHelper.TX_CONTRA,contraYorNo);
db.insert(VivzHelper.TX_TABLE, null, contentvalues);
String td = new SimpleDateFormat("dd-MM-yyyy").format(new Date());
}
data retrieval:
String name = titlesofReports.tagExpensesOrIncome;
SQLiteDatabase db = helper.getReadableDatabase();
String[] columns = { helper.TX_UID, helper.TX_NAME, helper.TX_PARTICULARS,
helper.TX_AMOUNT, helper.TX_DATE,helper.TX_CONTRA};
Cursor c = db.query(VivzHelper.TX_TABLE, columns, (helper.TX_ID + "='" + name + "' AND " + helper.TX_DATE + "= '" + td + "'"), null, null, null,null);
gt = 0;
gt_selectedItem_number = 0;
if (c != null) {
c.moveToFirst();
while (c.isAfterLast() == false) {
String v_uid=(c.getString(0));
String txTotal = (c.getString(3));
Float dd=Float.parseFloat(txTotal);
gt = gt + new Float(txTotal);
BigDecimal bdtxTotal= new BigDecimal(c.getString(3));
}
Using breakpoints, when I verified I could see all the 4 variables like
txTotal,dd1,dd,bdTxTotal are giving the same result like 12345.7 instead of 12345.67.
So I am working on a small program in Java. Basically I want the user to search a database with one or 1-3 search query and they can use any combination.
A search query example would be: Book Name, ISBN, Author Name
The user can search with any combination (Search by book name only, or book name and author name, or all 3 etc...).
I want to basically write one master SQL statement (MYSQL), that would pull the results from the database. The problem is, I don't know what to do with a blank input.
So say user enters:
Book name = Harry Potter and the Chamber of Secrets
ISBN = << left blank>>
Author Name = JK Rowling
An example SQL query would be:
SELECT *
FROM booklist
WHERE book_name = "Harry Potter and the Chamber of Secrets"
AND ISBN = ""
AND Author = "JK Rowling";
In Java code I am using PreparedStatement, and the String would be:
String temp = " SELECT * " +
" FROM booklist " +
" WHERE Title = " + title +
" AND Author = \"" + author + "\"" +
" AND ISBN = \"" + isbn + "\"";
Because the user did not enter ISBN, the SQL query fails (hence code fails). If I use null instead of "", then the query will still fail.
By fail meaning that it will not find the correct book in database (even though its present), as it is still looking for "" or null in the column.
Is there any way to pass kind of like a 'ghost' or invisible variable to get the SQL query to work like I am intending it to?
Or do I have to go the long way and make a SQL query for each possible combination?
Use OR instead of AND
Change:
String temp = " SELECT * " +
" FROM booklist " +
" WHERE Title = " + title +
" AND Author = \"" + author + "\"" +
" AND ISBN = \"" + isbn + "\"";
To:
String temp = " SELECT * FROM booklist " +
" WHERE Title = ? OR Author = ?" +
" OR ISBN = ?";
And then set the parameters for prepared statement.
pst.setString( 1, title );
pst.setString( 2, author );
pst.setString( 3, isbn );
With the OR if any of the matching records are found then they are fetched.
And, if you still want to use AND for comparison and want to not include empty inputs then you have to dynamically prepare the statement in JAVA.
StringBuilder sql = new StringBuilder( 1024 );
sql.append( " SELECT * FROM booklist " );
String whereCondition = "";
if( title != null && title.trim().length() > 0 ) {
whereCondition += " title = ?";
}
if( isbn != null && isbn.trim().length() > 0 ) {
whereCondition += (whereCondition.length() > 0 ? " AND " : "" );
whereCondition += " isbn = ?";
}
if( author != null && author.trim().length() > 0 ) {
whereCondition += (whereCondition.length() > 0 ? " AND " : "" );
whereCondition += " author = ?";
}
sql.append( " where " ).append( whereCondition );
pst = con.prepareStatement( sql.toString() );
Now set the prepared parameters like this:
And then set the parameters for prepared statement.
int paramIndex = 1;
if( title != null && title.trim().length() > 0 ) {
pst.setString( paramIndex++, title );
}
if( isbn != null && isbn.trim().length() > 0 ) {
pst.setString( paramIndex++, isbn );
}
if( author != null && author.trim().length() > 0 ) {
pst.setString( paramIndex++, author );
}
Now, you can execute the statement and fetch the resultset.
Lets assume, that we have some 2 tables in SQLite: TBL_PRODUCT and TBL_PRODUCT_ALIASES. Now, I want to query some data from joined two tables:
String sql = "SELECT " + TBL_PRODUCT + "." + C_PROD_PKEY_ID + ", " + TBL_PRODUCT_ALIASES + "." + C_PROD_ALIASES_PKEY_ID +
" FROM " + TBL_PRODUCT + " LEFT JOIN " + TBL_PRODUCT_ALIASES + " ON " + TBL_PRODUCT + "." + C_PROD_PKEY_ID + " = " + TBL_PRODUCT_ALIASES + "." + C_PROD_ALIASES_PKEY_ID +
" WHERE " + C_PROD_SERVER_ID + " = ? LIMIT 1";
Cursor cursor = SQLiteDataHelper.getInstance().rawQuery(sql, new String[] {"" + js_CartProduct.getLong("prod_id")});
Thats works great without any problem. And then I want to acquire some data from the returned cursor:
if (cursor.getCount() > 0) {
cursor.moveToFirst();
Long prodId = cursor.getLong(cursor.getColumnIndexOrThrow(TBL_PRODUCT + "." + C_PROD_PKEY_ID));
//... Some other code
}
Now, here is the problem: C_PROD_PKEY_ID and C_PROD_ALIASES_PKEY_ID are in the real world the same Strings: "_id". And as the result getLong() returns long not from the needed column of cursor.
How should I correctly address to the needed column? Are there other methods besides using AS in sql query OR/AND using definite numbers in cursor.getLong(0) instead of cursor.getLong(cursor.getColumnIndexOrThrow(TBL_PRODUCT + "." + C_PROD_PKEY_ID))?
Update:
cursor.getColumnNames() returns this: [_id, _id].