Giới thiệu
Ví dụ này minh họa cách truy vấn các bản ghi của ngày hôm qua (yesterday) dựa trên cột timestamp (datetime) trong SQLite Android.
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền đầy đủ thông tin cần thiết.
Bước 2: Thiết kế giao diện (res/layout/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"
android:orientation="vertical"
tools:context=".MainActivity">
<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">
<Button
android:id="@+id/save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lưu" />
<Button
android:id="@+id/refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Xem hôm qua" />
<Button
android:id="@+id/update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cập nhật" />
<Button
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Xóa tất cả" />
</LinearLayout>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Bước 3: MainActivity.java
package com.example.andy.myapplication;
import android.os.Bundle;
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 androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
Button save, refresh, update, delete;
EditText name, salary;
ListView listView;
DatabaseHelper helper;
ArrayAdapter arrayAdapter;
ArrayList arrayList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
helper = new DatabaseHelper(this);
arrayList = new ArrayList<>(helper.getAllContacts());
name = findViewById(R.id.name);
salary = findViewById(R.id.salary);
listView = findViewById(R.id.listView);
save = findViewById(R.id.save);
refresh = findViewById(R.id.refresh);
update = findViewById(R.id.update);
delete = findViewById(R.id.delete);
arrayAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, arrayList);
listView.setAdapter(arrayAdapter);
delete.setOnClickListener(v -> {
if (helper.deleteAll()) {
Toast.makeText(this, "Đã xóa", Toast.LENGTH_LONG).show();
refreshList();
} else {
Toast.makeText(this, "Xóa thất bại", Toast.LENGTH_LONG).show();
}
});
update.setOnClickListener(v -> {
String n = name.getText().toString().trim();
String s = salary.getText().toString().trim();
if (!n.isEmpty() && !s.isEmpty()) {
if (helper.update(n, s)) {
Toast.makeText(this, "Đã cập nhật", Toast.LENGTH_LONG).show();
refreshList();
} else {
Toast.makeText(this, "Cập nhật thất bại", Toast.LENGTH_LONG).show();
}
} else {
name.setError("Nhập tên");
salary.setError("Nhập lương");
}
});
refresh.setOnClickListener(v -> refreshList());
save.setOnClickListener(v -> {
String n = name.getText().toString().trim();
String s = salary.getText().toString().trim();
if (!n.isEmpty() && !s.isEmpty()) {
if (helper.insert(n, s)) {
Toast.makeText(this, "Đã thêm", Toast.LENGTH_LONG).show();
refreshList();
name.setText("");
salary.setText("");
} else {
Toast.makeText(this, "Thêm thất bại", Toast.LENGTH_LONG).show();
}
} else {
name.setError("Nhập tên");
salary.setError("Nhập lương");
}
});
}
private void refreshList() {
arrayList.clear();
arrayList.addAll(helper.getAllContacts());
arrayAdapter.notifyDataSetChanged();
}
}
Bước 4: DatabaseHelper.java
package com.example.andy.myapplication;
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;
class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "salaryDatabase5";
private static final String TABLE_NAME = "SalaryDetails";
private static final int DATABASE_VERSION = 1;
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE " + TABLE_NAME + " (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT, " +
"salary TEXT, " +
"datetime DEFAULT CURRENT_TIMESTAMP)";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
boolean insert(String name, String salary) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("name", name);
cv.put("salary", salary);
long result = db.insert(TABLE_NAME, null, cv); // Dùng insert cho AUTOINCREMENT
return result != -1;
}
// QUAN TRỌNG: Truy vấn bản ghi hôm qua
ArrayList getAllContacts() {
SQLiteDatabase db = getReadableDatabase();
ArrayList list = new ArrayList<>();
// SQLite date modifiers: 'now', '-1 day', 'start of day', etc.
// DATE(datetime) trích xuất phần ngày từ timestamp
// DATE('now', '-1 day') = ngày hôm qua (theo UTC)
String query = "SELECT (id || ' : ' || name || ' : ' || salary || ' : ' || datetime) AS fullname " +
"FROM " + TABLE_NAME +
" WHERE DATE(datetime) = DATE('now', '-1 day')";
Cursor res = db.rawQuery(query, null);
if (res.moveToFirst()) {
do {
list.add(res.getString(res.getColumnIndexOrThrow("fullname")));
} while (res.moveToNext());
}
res.close();
if (list.isEmpty()) {
list.add("Không có bản ghi nào cho ngày hôm qua");
}
return list;
}
boolean update(String name, String salary) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("name", name);
cv.put("salary", salary);
int rows = db.update(TABLE_NAME, cv, null, null); // CẢNH BÁO: không WHERE
return rows > 0;
}
boolean deleteAll() {
SQLiteDatabase db = getWritableDatabase();
int rows = db.delete(TABLE_NAME, null, null);
return rows > 0;
}
}
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Thêm vài bản ghi hôm nay và hôm qua (hoặc chỉnh thời gian thiết bị), nhấn Xem hôm qua.
Kết quả
ListView chỉ hiển thị các bản ghi có datetime rơi vào ngày hôm qua:
1 : Nguyễn Văn A : 10000000 : 2024-01-14 08:30:00 2 : Trần Thị B : 15000000 : 2024-01-14 14:22:00
Giải thích hàm DATE() và modifier trong SQLite
| Cú pháp | Kết quả |
|---|---|
DATE('now') | Hôm nay (UTC) |
DATE('now', '-1 day') | Hôm qua (UTC) |
DATE('now', '+1 day') | Ngày mai (UTC) |
DATE('now', 'start of month') | Ngày 1 của tháng này |
DATE('now', '-1 month') | Tháng trước ngày hôm nay |
DATETIME('now', 'localtime') | Giờ địa phương (không phải UTC) |
Lưu ý về múi giờ (Timezone)
SQLite lưu CURRENT_TIMESTAMP theo UTC. Hàm DATE('now') cũng trả về ngày UTC.
Nếu cần theo múi giờ địa phương:
-- Chuyển datetime sang local time trước khi lấy DATE
WHERE DATE(datetime, 'localtime') = DATE('now', 'localtime', '-1 day')
Lưu ý: Code gốc dùng res.isAfterLast() == false (logic ngược). Đã sửa dùng moveToFirst() + do-while. Cũng thêm xử lý list rỗng. Cảnh báo UPDATE không WHERE.