I'm having some difficulty understanding the update command for SQLite.
In my example I am perform an update database, but if there's an error I'm delivering an error message. If the user trys to update a record that doesn't exist, I'm not getting an error message.
Here is my code, first the update command, and then my call:
public long updateContact(String firstName, String lastName, String address, String city, String state,
int zipCode, long mobileNumber, long altNumber, String email) {
ContentValues contactInfo = new ContentValues();
contactInfo.put(KEY_FNAME, firstName);
contactInfo.put(KEY_LNAME, lastName);
contactInfo.put(KEY_ADDR, address);
contactInfo.put(KEY_CITY, city);
contactInfo.put(KEY_STATE, state);
contactInfo.put(KEY_ZIP, zipCode);
contactInfo.put(KEY_MOBILE, mobileNumber);
contactInfo.put(KEY_ALT, altNumber);
contactInfo.put(KEY_EMAIL, email);
String where = "FIRSTNAME = '" + firstName + "' AND LASTNAME = '" + lastName + "'";
return db.update(DATABASE_TABLE, contactInfo, where, null);
}
The call:
if (searchTerm.length() > 0) {
id = db.updateContact(fName, lName, address.getText().toString().trim(),
city.getText().toString().trim(), state.getSelectedItem().toString().trim(), Integer.parseInt(zip.getText().toString().trim()),
Long.valueOf(mobile.getText().toString().trim()), Long.valueOf(alternate.getText().toString().trim()),
email.getText().toString().trim());
if (id == -1) {
DisplayErrorDialog("I'm sorry, we can not update the contact with the present data.");
}
}
The update is working when I give it valid data. But when I give it invalid data (name that isn't in the database), I'm not getting the appropriate error message.
From the fine manual:
Returns
the number of rows affected
So db.update will return 0 when nothing was updated (i.e. your where didn't match any rows) and that zero will be returned by updateContact. So you probably want to rename id to numberUpdated (or similar) and show on error on numberUpdated <= 0 instead of looking for a -1.
The return value is the number of rows updated, not the id. Check for 0, not -1. This implies you could be updating more than one record, which is how database updates work generally.
Related
I am making a app that incorporates login/register functionalities and I'm making a issue that I have been trying to solve.
When a user logins and the login is successful, I'd like to use the email that they signed in with to pass to the next activity using Intent (I checked that the email is in fact getting passed by displaying what is being passed through the intent) and then passing that email to a function in the Dbhelper that uses that email to look for the name of the person that signed in then displaying "Welcome (name of person)" in the current activity but I keep getting a null returned in the function which ultimately leads to the app crashing.
Here is where I'm calling the function in the activity where I want to display the name.
if(!session.loggedIn())
{
Logout();
}
else
{
Intent in = getIntent();
String email = in.getStringExtra("email");
Name.setText("Welcome " + db.findName(email));
}
And this is the function in my DbHelper.java where I'm looking for the name with a query and such.
public String findName(String user_email)
{
String query = "SELECT " + COLUMN_NAME + " FROM " + USER_TABLE + " WHERE " + COLUMN_EMAIL + " = " + "'" + user_email + "'";
SQLiteDatabase db = this.getWritableDatabase();
//reads for database
Cursor c = db.rawQuery(query, null);
c.moveToFirst();
if(c.getCount() > 0) // if cursor is not empty
{
String n = c.getString(0);
return n;
}
else
{
return null;
}
}
As you can see, it's returning null. And yes there is entries in the database already. Also, I tried just passing the email to the function and returning what was passed and it still gave me an error.
Normally, to check for a value in a text column, you do not use the equal = sign, but rather WHERE Column LIKE '%text%'. Also, when saving to a database you should escape and "sanitize" strings. If you did this, then you should also be doing the same process when looking for them, else you won't find them.
I am telling you this since, even if you are sure there are entries in your table, the result of the query may be empty. You could just debug by printing the result of the c.getCount() call or something.
String sql2="if not exists(select * FROM stock where productCode=?)\n" +
"Begin\n" +
"insert into stock "
+ "(productName,quantity,currentQuantity,price,companyName,categoryName,productCode) "
+ "values(?,?,?,?,?,?,?)\n" +
"End";
PreparedStatement pst2 = con.prepareStatement(sql2);
pst2.setString(1,productCodeTextField.getText());
pst2.setString(2,productNameTextField.getText());
pst2.setString(3,quantityTextField.getText());
pst2.setString(4,quantityTextField.getText());
pst2.setString(5,priceTextField.getText());
pst2.setString(6, (String) companyNameJComboBox.getSelectedItem());
pst2.setString(7, (String) categoryNameJComboBox.getSelectedItem());
pst2.setString(8,productCodeTextField.getText());
int x=pst2.executeUpdate();
if(x!=0){
productCodeTextField.setText("");
productNameTextField.setText("");
quantityTextField.setText("");
priceTextField.setText("");
JOptionPane.showMessageDialog(null,"Product entered");
}else{
JOptionPane.showMessageDialog(null,"Product already exists");
}
I am successfully able to check for for already existing products before insertion but i am not able to populate the correct message on the basis of the query executed. The executeUpdate is always returning some value even when the insertion is not being done. How to fix this.
There is an easier solution that may work for you:
Throw away the first query that checks whether the entry already exists
Rewrite sql2 as follows:
INSERT INTO stock
(productCode, productName, quantity, price, companyName, categoryName)
VALUES (?,?,?,?,?,?)
WHERE NOT EXISTS
(SELECT * FROM stock WHERE productCode = ?)
Add: pst.setString(7, productCodeTextField.getText());
executeUpdate() returns an int indicating the number of rows affected by the query. Use this variable to determine if a row was added. If the variable != 0 display success message.
INSERT INTO stock
(productCode, productName, quantity, price, companyName, categoryName)
select ?,?,?,?,?,?
WHERE NOT EXISTS
(SELECT * FROM stock WHERE productCode = ?)
This is how it works for SQL Server. 3 and 4 points same as Coop answered
I have a Spring application with a update API endpoint for a Postgres database. The user can submit information and updates will be reflected in the database. The user only submits what they have to update. For example consider the following object:
class Dog {
String name;
int age;
String breed;
// Attributes and getters/setters...
}
When the user submits a update request, they only send the information they wish to update, such as only name and breed. I have the following function that updates the database with information:
public void update(String name, int age, String breed, JdbcTemplate template) {
UpdateBuilder query = new UpdateBuilder();
query.from("DogTable");
boolean updated = false;
if (name != null) {
query.set("name" + " = '" + name + "'");
updated = true;
}
if (age != null) {
query.set("age" + " = '" + age + "'");
updated = true;
}
if (breed != null) {
query.set("breed" + " = '" + breed + "'");
updated = true;
}
// And so on...
if (updated) {
query.set("UpdatedTime" + " = '" + new Date() + "'");
}
query.where("someKey" + " = '" + someId + "'");
template.update(query.toString());
}
(The query.set() stuff is just a helper class that builds a query string)
As you can see, this gets messy with all the "is the name given, is the age given?" checks. That leads to my question: Is there a data driven approach to do this? What I would like to be able to do is:
myJdbcTemplate.update(ListOfObjectsToUpdate, "TableName");
Simply, the JDBC template would see what I have provided it, and would proceed to update the provided table with that information. Is this even possible? I realize that building queries using strings is bad, but PreparedStatements don't look much better in code (not to mention, they don't solve this issue).
You can use the COALESCE function for this purpose - add user value as well and existing value and if the user value is not null (intended update) it well be set as the new value.
Similar to this -
UPDATE "user" SET alternate_contact_name = COALESCE(<user value>, alternate_contact_name)
This is a MySQL query but COALESCE works same way in Postgresql
The user value will be set and new value if it is not null. When it is null and original value of column is not null, the original value if picked. If both are null then it doesn't matter.
WIth this you can simply pass all parameters and avoid building query in an untidy way.
I'm writing a basic android app in which personal information like name, email, etc. is filled in and stored in an SQLite database by pressing a "submit"-button (this all works perfectly). Then there's a search button which should search for a corresponding person in the database when one field is filled in (e.g. only the field name is given a string "harry" and the other fields keep a null-value). This is the corresponding code in my DatabaseHelper class:
public Person getPerson(String naam, String adres, String email, String geslacht,
String leeftijd, String geboortedatum){
Log.i("Main activity","Person to find: "+naam);
SQLiteDatabase db= this.getReadableDatabase();
Cursor curs=db.rawQuery("SELECT name FROM personen WHERE (name = ?) OR (adress = ?) "
+ "OR (email = ?) OR (gender = ?) OR (age = ?) OR (birthday = ?)",
new String[]{naam, adres, email, geslacht, leeftijd, geboortedatum});
Log.i("Main activity", "Query works");
I used the logs to make sure where the error is thrown and found that the rawQuery does work when all the args[] fields are given a value, but gives an error when one field (e.g. email) contains a null value. Isn't this why I should use the OR statement instead of the AND statement? If not, how can I make it work when not all fields are filled in in the app?
A fast fix should be to do something like that:
new String[]{naam == null? "''":naam, etc}
Check if your sting is initialized, if it is not, replace it by a dummy value.
rawQuery() expects a string array, but null is not a valid string.
You'd have to put the NULL directly into the SQL string, without a parameter.
But when you're constructing the string dynamically anyway, you can just as well leave out that comparison.
search by name:
// Getting single contact
Contact getContact(String name) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_CONTACTS, new String[] { KEY_ID,
KEY_NAME, KEY_PH_NUM }, KEY_NAME + "=?",
new String[] { name }, null, null, null, null);
//...
for access:
Contact contact = null;
if (cursor.moveToFirst()) {
contact = new Contact(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2));
}
cursor.close();
// can return null if no contact was found.
return contact;
I use this code to update a contact's address, but it only works for contacts that have an existing address. If the contact address field is empty, the update() method returns zero and the contact data is not updated. How do I add an address to an existing contact?
//str_id is the contact's ID
//input is the String representing an address
ContentValues cv = new ContentValues();
String[] params = new String[] { str_id, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE };
cv.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, input);
getContentResolver().update(ContactsContract.Data.CONTENT_URI, cv, ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?", params);
I have also tried the equivalent logic with a ContentProviderOperation, but get the same result. Just like my previous example, I can update an existing address but cannot create an address.
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, id)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, input)
.build());
You need to check whether Adress exist or not before updating Address,
If address exist your above code will work fine as you are doing just update..
While doing insert address, actually you are doing a child insert" see here, Very good explanation of ContentProviderOperation which relates to your issue closely..