Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách lấy bản ghi theo ngày cụ thể từ timestamp SQLite Android

Giới thiệu

Ví dụ này minh họa cách truy vấn các bản ghi của một ngày cụ thể (specific date) 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 ngày 13/01/2019" />

        <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);
        return result != -1;
    }

    // QUAN TRỌNG: Truy vấn bản ghi theo ngày CỤ THỂ
    ArrayList getAllContacts() {
        SQLiteDatabase db = getReadableDatabase();
        ArrayList list = new ArrayList<>();
        
        // DATE(datetime) = 'YYYY-MM-DD' (định dạng ISO 8601)
        // Ví dụ: 13-01-2019 -> '2019-01-13'
        String query = "SELECT (name || ' : ' || salary || ' : ' || datetime) AS fullname " +
                       "FROM " + TABLE_NAME + 
                       " WHERE DATE(datetime) = '2019-01-13'";
        
        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 2019-01-13");
        }
        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 bản ghi với ngày 13/01/2019 (hoặc chỉnh thời gian thiết bị), nhấn Xem ngày 13/01/2019.

Kết quả

ListView hiển thị các bản ghi có datetime rơi vào ngày 13-01-2019:

Nguyễn Văn A : 10000000 : 2019-01-13 08:30:00
Trần Thị B : 15000000 : 2019-01-13 14:22:00

Giải thích truy vấn theo ngày cụ thể

Định dạng ngày chuẩn SQLite: YYYY-MM-DD (ISO 8601)

  • DATE(datetime) = '2019-01-13' - So sánh phần ngày của cột datetime với chuỗi cố định
  • SQLite tự động parse '2019-01-13' thành date
  • Khớp mọi thời gian trong ngày đó (00:00:00 đến 23:59:59)

Các cách truy vấn ngày khác nhau

Mục đíchWHERE clause
Ngày cụ thểDATE(datetime) = '2019-01-13'
Khoảng ngàyDATE(datetime) BETWEEN '2019-01-01' AND '2019-01-31'
Tháng cụ thểstrftime('%Y-%m', datetime) = '2019-01'
Năm cụ thểstrftime('%Y', datetime) = '2019'
Ngày trong tuần (CN=0)strftime('%w', datetime) = '1' (Thứ 2)

Truy vấn an toàn với tham số (Parameterized Query)


// Trong Java code - an toàn SQL Injection
String targetDate = "2019-01-13";
String query = "SELECT * FROM " + TABLE_NAME + " WHERE DATE(datetime) = ?";
Cursor res = db.rawQuery(query, new String[]{targetDate});

Lưu ý: Code gốc nhúng cứng ngày '2019-01-13' trong SQL. Đã thêm giải thích định dạng ISO 8601, các hàm strftime, và cách dùng parameterized query an toàn. Cảnh báo UPDATE không WHERE.