Nhập môn SQL

Nhập môn SQL

Khoá học Phát triển ứng dụng Android bằng Kotlin giả định rằng bạn đã quen thuộc với các chủ đề sau:

  • Cơ sở dữ liệu nói chung
  • Cụ thể là các cơ sở dữ liệu SQL
  • Ngôn ngữ SQL dùng để tương tác với cơ sở dữ liệu

Trang này cung cấp thông tin giúp bạn gợi nhớ và tham khảo nhanh.

Cơ sở dữ liệu SQL

Cơ sở dữ liệu SQL lưu trữ dữ liệu trong bảng theo hàng và cột:

  • Giao điểm của một hàng và cột được gọi là trường (field).
  • Các trường này chứa dữ liệu, tham chiếu đến các trường khác hoặc tham chiếu đến các bảng khác.
  • Mỗi hàng chứa một thực thể (entity). Thực thể được xác định bằng một mã nhận dạng duy nhất, thường được dùng làm khoá chính.
  • Mỗi cột được xác định bằng một tên duy nhất cho mỗi bảng.

SQLite

SQLite triển khai một công cụ cơ sở dữ liệu SQL có các đặc điểm sau:

  • Tự chứa (không cần thành phần nào khác)
  • Không máy chủ (không cần phần phụ trợ máy chủ)
  • Không định cấu hình (không cần định cấu hình cho ứng dụng của bạn)
  • Giao tác (các thay đổi trong một giao dịch trong SQLite xảy ra hoàn toàn hoặc không hề xảy ra)

SQLite là công cụ cơ sở dữ liệu được triển khai rộng rãi nhất trên thế giới. Mã nguồn cho SQLite thuộc phạm vi công cộng. Để biết thông tin chi tiết về cơ sở dữ liệu SQLite, hãy xem trang web của SQLite.

Bảng ví dụ

  • Cơ sở dữ liệu có tên DATABASE_NAME
  • Bảng có tên WORD_LIST_TABLE
  • Các cột cho _id, worddefinition

Sau khi chèn các từ (word) alphabeta (trong đó alpha có hai định nghĩa (definition)), bảng có thể có dạng như sau:

DATABASE_NAME

WORD_LIST_TABLE

_id

word

definition

1

"alpha"

"first letter"

2

"beta"

"second letter"

3

"alpha"

"particle"

Để tìm nội dung trong một hàng cụ thể, hãy sử dụng _id hoặc truy xuất các hàng bằng cách lập phương thức truy vấn chọn hàng trong bảng bằng cách chỉ định các quy tắc ràng buộc.

Giao dịch

Giao dịch (transaction) là một chuỗi thao tác được thực hiện dưới dạng một đơn vị logic công việc (work) duy nhất. Để đủ điều kiện xuất hiện dưới dạng một giao dịch, đơn vị logic của công việc phải thể hiện 4 đặc điểm: tính nguyên tố (atomicity), tính nhất quán (consistency), tính độc lập (isolation) và tính bền vững (durability), gọi tắt là ACID:

  • Tính nguyên tố. Tất cả thao tác sửa đổi dữ liệu của một giao dịch đều được thực hiện hoặc không có thao tác sửa đổi nào được thực hiện. Tính nguyên tố vẫn đúng ngay cả khi sự cố chương trình, sự cố hệ điều hành hoặc lỗi nguồn điện làm gián đoạn hoạt động ghi thay đổi vào đĩa.
  • Tính nhất quán. Khi hoàn tất, giao dịch phải để tất cả dữ liệu ở trạng thái nhất quán.
  • Tính độc lập. Nội dung sửa đổi do các giao dịch đồng thời thực hiện phải được tách biệt với nội dung sửa đổi do các giao dịch đồng thời thực hiện. Một giao dịch hoặc là nhận ra dữ liệu ở trạng thái mà dữ liệu từng có trước một giao dịch đồng thời khác đã sửa đổi dữ liệu đó, hoặc là nhận ra dữ liệu sau khi giao dịch thứ hai đã hoàn tất. Giao dịch không nhận ra trạng thái trung gian.
  • Tính bền vững. Sau khi giao dịch hoàn tất, giao dịch sẽ có hiệu lực vĩnh viễn trong hệ thống. Nội dung sửa đổi vẫn tồn tại ngay cả trong trường hợp xảy ra lỗi hệ thống.

Ví dụ về giao dịch:

  • Chuyển tiền từ tài khoản tiết kiệm sang tài khoản vãng lai.
  • Nhập một thuật ngữ và định nghĩa vào từ điển.
  • Đưa changelist vào nhánh chính.

Để biết thêm thông tin về giao dịch, hãy xem nội dung Cam kết nguyên tử trong SQLite.

Ngôn ngữ truy vấn

Bạn sử dụng ngôn ngữ truy vấn SQL để tương tác với cơ sở dữ liệu. Các truy vấn có thể rất phức tạp, nhưng có 4 hoạt động cơ bản:

  • Chèn hàng
  • Xoá hàng
  • Cập nhật giá trị trong hàng
  • Truy xuất hàng đáp ứng tiêu chí đã cho

Trên Android, đối tượng truy cập dữ liệu (DAO) cung cấp các phương thức thuận tiện để chèn, xoá và cập nhật cơ sở dữ liệu. Để xem mô tả đầy đủ về ngôn ngữ truy vấn, hãy xem nội dung SQL theo cách hiểu của SQLite

Cấu trúc truy vấn

Truy vấn SQL được cấu trúc ở mức cao. Truy vấn mẫu:

  • SELECT word, definition FROM WORD_LIST_TABLE WHERE word="alpha"

Phiên bản chung của truy vấn mẫu:

  • SELECT columns FROM table WHERE column="value"

Các phần của truy vấn mẫu:

  • SELECT columns: Chọn các cột (column) cần trả lại. Sử dụng * để trả về tất cả các cột.
  • FROM table: Chỉ định bảng (table) mà bạn sẽ nhận kết quả.
  • WHERE: Từ khoá không bắt buộc đứng trước điều kiện phải đáp ứng, ví dụ: column="value". Có một số toán tử phổ biến là =, LIKE, <>. Để kết nối nhiều điều kiện, hãy sử dụng AND hoặc OR.

Các phần khác của truy vấn:

  • ORDER BY: Cụm từ khoá không bắt buộc để sắp xếp kết quả theo một cột. Chỉ định ASC để tăng dần và DESC để giảm dần. Nếu không chỉ định thứ tự, bạn sẽ nhận được thứ tự mặc định (có thể lộn xộn).
  • LIMIT: Từ khoá để xác định số lượng kết quả có hạn.

Truy vấn và kết quả mẫu

Các truy vấn sau đây sử dụng bảng được xác định trước ở trên:

SELECT * FROM WORD_LIST_TABLE

Lấy tất cả các hàng (row) trong bảng WORD_LIST_TABLE.
SELECT word, definition FROM WORD_LIST_TABLE WHERE _id > 2 Chọn cột worddefinition của tất cả các mục có id lớn hơn 2.
Trả về

[["alpha", "particle"]]

SELECT _id FROM WORD_LIST_TABLE WHERE word="alpha" AND definition LIKE "%art%"

Trả về id của từ alpha với chuỗi con art trong định nghĩa.

[["3"]]

SELECT definition FROM WORD_LIST_TABLE ORDER BY word DESC LIMIT 1

Chọn tất cả định nghĩa. Sắp xếp theo chiều ngược lại và lấy hàng đầu tiên sau khi danh sách được sắp xếp. Sắp xếp theo cột được chỉ định là word. Xin lưu ý rằng chúng ta có thể sắp xếp theo một cột mà chúng ta không trả về!

[["second letter"]]

SELECT * FROM WORD_LIST_TABLE LIMIT 2,1

Trả về 1 mục bắt đầu từ vị trí 2. Vị trí sẽ bắt đầu tại 1 (không phải là 0!). Trả về [["2", "beta", "second letter"]]

Bạn có thể thực hành tạo và truy vấn cơ sở dữ liệu tại trang web SQL Fiddle này.

Truy vấn dành cho Android SQLite

Bạn có thể gửi truy vấn đến cơ sở dữ liệu SQLite của hệ thống Android dưới dạng truy vấn thô hoặc dưới dạng tham số.

Phương thức rawQuery(String sql, String[] selectionArgs) chạy SQL đã cung cấp. Phương thức này sẽ trả về Cursor của tập hợp kết quả. Bảng sau đây cho thấy 2 truy vấn mẫu đầu tiên từ trên sẽ trông như thế nào dưới dạng truy vấn thô:

1

String query = "SELECT * FROM WORD_LIST_TABLE";
rawQuery(query, null);

2

query = "SELECT word, definition FROM WORD_LIST_TABLE WHERE _id> ? ";
String[] selectionArgs = new String[]{"2"}
rawQuery(query, selectionArgs) ;

Phương thức query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) truy vấn bảng đã cho. Phương thức này trả về một Cursor trong tập hợp kết quả. Sau đây là truy vấn cho thấy cách điền đối số:

SELECT * FROM WORD_LIST_TABLE
WHERE word="alpha"
ORDER BY word ASC LIMIT 2,1;

Truy vấn trả về nội dung sau:

[["alpha", "particle"]]

Ví dụ về các đối số mà bạn có thể sử dụng:

String table = "WORD_LIST_TABLE"
String[] columns = new String[]{"*"};
String selection = "word = ?"
String[] selectionArgs = new String[]{"alpha"};
String groupBy = null;
String having = null;
String orderBy = "word ASC"
String limit = "2,1"

query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit);

Lưu ý: Trong mã trên thực tế, bạn sẽ không tạo biến cho giá trị null. Hãy xem tài liệu SQLiteDatabase Android cho các phiên bản của phương thức này với nhiều tham số.

Con trỏ

Con trỏ (cursor) là một điểm trỏ tới một hàng dữ liệu có cấu trúc. Bạn có thể coi con trỏ là điểm trỏ tới hàng trong bảng.

Một truy vấn trả về một đối tượng Cursor trỏ đến thành phần đầu tiên trong kết quả truy vấn. Lớp Cursor cung cấp các phương thức để di chuyển con trỏ thông qua kết quả truy vấn và các phương thức để lấy dữ liệu từ các cột của từng hàng trong kết quả.

Khi một phương thức trả về đối tượng Cursor, bạn sẽ lặp lại kết quả, trích xuất dữ liệu, thực hiện thao tác nào đó với dữ liệu rồi đóng con trỏ để giải phóng bộ nhớ.

Tìm hiểu thêm