Lệnh UPDATE trong SQLite Android
Lệnh UPDATE sửa đổi dữ liệu hiện có trong bảng. Khác với REPLACE, UPDATE chỉ thay đổi các cột được chỉ định, giữ nguyên các cột khác và PRIMARY KEY.
Bước 1: Tạo dự án
Android Studio → File → New Project.
Bước 2: Giao diện (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:padding="16dp">
<EditText android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Nhập tên" />
<EditText android:id="@+id/salary" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Nhập lương" android:inputType="numberDecimal" />
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="8dp">
<Button android:id="@+id/save" android:text="Lưu" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<Button android:id="@+id/refresh" android:text="Làm mới" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<Button android:id="@+id/update" android:text="Cập nhật" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" />
</LinearLayout>
Bước 3: MainActivity.java
package com.example.sqliteupdate;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
Button btnSave, btnRefresh, btnUpdate;
EditText edtName, edtSalary;
ListView listView;
DatabaseHelper dbHelper;
ArrayList dataList;
ArrayAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new DatabaseHelper(this);
dataList = new ArrayList<>(dbHelper.getAllContacts());
edtName = findViewById(R.id.name);
edtSalary = findViewById(R.id.salary);
listView = findViewById(R.id.listView);
btnSave = findViewById(R.id.save);
btnRefresh = findViewById(R.id.refresh);
btnUpdate = findViewById(R.id.update);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataList);
listView.setAdapter(adapter);
btnRefresh.setOnClickListener(v -> refreshList());
btnSave.setOnClickListener(v -> {
String name = edtName.getText().toString().trim();
String salary = edtSalary.getText().toString().trim();
if (name.isEmpty() || salary.isEmpty()) {
showError(name, salary);
return;
}
if (dbHelper.insert(name, salary)) {
Toast.makeText(this, "Đã thêm", Toast.LENGTH_SHORT).show();
refreshList();
} else {
Toast.makeText(this, "Thêm thất bại", Toast.LENGTH_SHORT).show();
}
});
btnUpdate.setOnClickListener(v -> {
String name = edtName.getText().toString().trim();
String salary = edtSalary.getText().toString().trim();
if (name.isEmpty() || salary.isEmpty()) {
showError(name, salary);
return;
}
// UPDATE: Cập nhật salary cho bản ghi có name tương ứng
if (dbHelper.updateByName(name, salary)) {
Toast.makeText(this, "Đã cập nhật lương cho: " + name, Toast.LENGTH_SHORT).show();
refreshList();
} else {
Toast.makeText(this, "Không tìm thấy: " + name, Toast.LENGTH_SHORT).show();
}
});
}
private void refreshList() {
dataList.clear();
dataList.addAll(dbHelper.getAllContacts());
adapter.notifyDataSetChanged();
}
private void showError(String name, String salary) {
if (name.isEmpty()) edtName.setError("Nhập tên");
if (salary.isEmpty()) edtSalary.setError("Nhập lương");
}
}
Bước 4: DatabaseHelper.java - UPDATE an toàn
package com.example.sqliteupdate;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "salaryDatabase";
private static final String TABLE_NAME = "SalaryDetails";
private static final int DB_VERSION = 1;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME +
"(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, salary TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
public boolean insert(String name, String salary) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("name", name);
cv.put("salary", salary);
return db.insert(TABLE_NAME, null, cv) != -1;
}
public ArrayList getAllContacts() {
ArrayList list = new ArrayList<>();
SQLiteDatabase db = getReadableDatabase();
// Lọc: salary > 10 HOẶC name bắt đầu bằng 'Sa'
Cursor cursor = db.rawQuery(
"SELECT name FROM " + TABLE_NAME +
" WHERE salary > '10' OR name LIKE 'Sa%'", null);
if (cursor.moveToFirst()) {
do {
list.add(cursor.getString(cursor.getColumnIndex("name")));
} while (cursor.moveToNext());
}
cursor.close();
return list;
}
// UPDATE AN TOÀN: Dùng ContentValues + whereClause + whereArgs
public boolean updateByName(String name, String newSalary) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("salary", newSalary);
// WHERE name = ? - dùng tham số tránh SQL Injection
int rowsAffected = db.update(TABLE_NAME, cv, "name = ?", new String[]{name});
return rowsAffected > 0;
}
// UPDATE NHIỀU CỘT
public boolean updateFull(String name, String newName, String newSalary) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("name", newName);
cv.put("salary", newSalary);
return db.update(TABLE_NAME, cv, "name = ?", new String[]{name}) > 0;
}
// UPDATE CÓ ĐIỀU KIỆN PHỨC TẠP
public boolean updateSalaryWhere(String condition, String[] args, String newSalary) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("salary", newSalary);
return db.update(TABLE_NAME, cv, condition, args) > 0;
}
public boolean deleteAll() {
return getWritableDatabase().delete(TABLE_NAME, null, null) > 0;
}
}
Cú pháp UPDATE đầy đủ
-- Cú pháp cơ bản
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
-- Ví dụ
UPDATE SalaryDetails
SET salary = '5000', updated_at = CURRENT_TIMESTAMP
WHERE name = 'An';
-- UPDATE với subquery
UPDATE SalaryDetails
SET salary = salary * 1.1
WHERE id IN (SELECT id FROM SalaryDetails WHERE department = 'IT');
-- UPDATE JOIN (SQLite hỗ trợ qua subquery)
UPDATE SalaryDetails
SET bonus = (SELECT rate FROM BonusRate WHERE level = SalaryDetails.level)
WHERE EXISTS (SELECT 1 FROM BonusRate WHERE level = SalaryDetails.level);
Best Practices quan trọng
- Luôn dùng WHERE - Không có WHERE = cập nhật TẤT CẢ hàng.
- Dùng ContentValues + whereArgs - Tránh SQL Injection, xử lý escape tự động.
- Kiểm tra rowsAffected - Trả về số dòng bị ảnh hưởng, 0 = không tìm thấy.
- Transaction cho batch update:
db.beginTransaction();
try {
for (Item item : items) {
ContentValues cv = new ContentValues();
cv.put("status", item.status);
db.update(TABLE, cv, "id = ?", new String[]{String.valueOf(item.id)});
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
⚠️ Lỗi thường gặp
- Quên WHERE → update toàn bảng.
- Ghép chuỗi SQL:
"UPDATE ... SET salary = '" + salary + "'"→ SQL Injection, lỗi quote. - UPDATE cột PRIMARY KEY → lỗi hoặc thay đổi identity.
- Không kiểm tra kết quả → im lặng khi không update được gì.
So sánh: db.update() vs db.execSQL()
| Phương thức | Ưu điểm | Nhược điểm |
|---|---|---|
| db.update() | An toàn, tự escape, trả về rows affected | Chỉ UPDATE đơn giản |
| db.execSQL() | Linh hoạt, subquery, expression phức tạp | Rủi ro SQL Injection, không trả về rows affected |