DISTINCT trong SQLite - Loại bỏ bản ghi trùng lặp
Từ khóa DISTINCT trong SQL dùng để trả về các giá trị duy nhất (unique), loại bỏ các dòng trùng lặp hoàn toàn trong kết quả truy vấn.
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.sqlitedistinct;
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;
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);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataList);
listView.setAdapter(adapter);
btnRefresh.setOnClickListener(v -> {
dataList.clear();
dataList.addAll(dbHelper.getAllContacts());
adapter.notifyDataSetChanged();
});
btnSave.setOnClickListener(v -> {
String name = edtName.getText().toString().trim();
String salary = edtSalary.getText().toString().trim();
if (name.isEmpty() || salary.isEmpty()) {
if (name.isEmpty()) edtName.setError("Nhập tên");
if (salary.isEmpty()) edtSalary.setError("Nhập lương");
return;
}
if (dbHelper.insert(name, salary)) {
Toast.makeText(this, "Đã thêm", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Thêm thất bại", Toast.LENGTH_SHORT).show();
}
});
}
}
Bước 4: DatabaseHelper.java - Quan trọng: DISTINCT
package com.example.sqlitedistinct;
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, datetime DEFAULT CURRENT_TIMESTAMP)");
}
@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;
}
// SỬ DỤNG DISTINCT ĐỂ LOẠI BỎ TRÙNG LẶP
public ArrayList getAllContacts() {
ArrayList list = new ArrayList<>();
SQLiteDatabase db = getReadableDatabase();
// Chỉ lấy tên duy nhất, sắp xếp theo name, salary
Cursor cursor = db.rawQuery(
"SELECT DISTINCT name FROM " + TABLE_NAME + " ORDER BY name, salary", null);
if (cursor.moveToFirst()) {
do {
list.add(cursor.getString(cursor.getColumnIndex("name")));
} while (cursor.moveToNext());
}
cursor.close();
return list;
}
public boolean update(String name, String salary) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("name", name);
cv.put("salary", salary);
return db.update(TABLE_NAME, cv, "name = ?", new String[]{name}) > 0;
}
public boolean deleteAll() {
return getWritableDatabase().delete(TABLE_NAME, null, null) > 0;
}
}
Giải thích DISTINCT
-- Chỉ lấy cột name duy nhất
SELECT DISTINCT name FROM SalaryDetails;
-- DISTINCT trên nhiều cột (kết hợp name + salary phải duy nhất)
SELECT DISTINCT name, salary FROM SalaryDetails;
-- Kết hợp với ORDER BY
SELECT DISTINCT name FROM SalaryDetails ORDER BY name ASC;
-- Kết hợp với COUNT
SELECT COUNT(DISTINCT name) FROM SalaryDetails;
So sánh: Không DISTINCT vs Có DISTINCT
Dữ liệu mẫu:
| id | name | salary |
|---|---|---|
| 1 | An | 1000 |
| 2 | Bình | 2000 |
| 3 | An | 1500 |
| 4 | Cường | 3000 |
| 5 | An | 1000 |
SELECT name FROM table: An, Bình, An, Cường, An (5 dòng)
SELECT DISTINCT name FROM table: An, Bình, Cường (3 dòng)
SELECT DISTINCT name, salary FROM table: (An,1000), (Bình,2000), (An,1500), (Cường,3000) (4 dòng)
Lưu ý hiệu năng
- DISTINCT tốn tài nguyên hơn (phải sort/hash để loại trùng).
- Nên tạo index trên cột dùng DISTINCT:
CREATE INDEX idx_name ON SalaryDetails(name); - Tránh
SELECT DISTINCT *- chỉ chọn cột cần thiết.