VieTopik
Tiếng HànTiếng AnhIT
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
SQL với OracleNối bảng
Bài 7/16
5 phút

Khoá ngoại và quan hệ

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Bảng orders không lưu tên khách, chỉ lưu customer_id. Tên, email, thành phố nằm ở bảng customers. Hai bảng nối với nhau qua cột này, và database phải chặn những đơn hàng trỏ tới một khách không tồn tại.

Khái niệm

🔗 Khoá ngoại (foreign key): cột trỏ tới khoá chính của một bảng khác, database không cho lưu giá trị không có bên bảng kia.

🌳 Quan hệ một-nhiều: một dòng ở bảng này ứng với nhiều dòng ở bảng khác, ví dụ một khách hàng có nhiều đơn hàng.

Ví dụ

Bảng orders trong script dữ liệu mẫu khai báo khoá ngoại như bản rút gọn dưới đây:

CREATE TABLE order_samples (
  order_id    NUMBER PRIMARY KEY,
  customer_id NUMBER NOT NULL
              REFERENCES customers (customer_id)
);
  • REFERENCES customers (customer_id): giá trị của cột phải có trong customers.customer_id.
  • Một khách có thể có nhiều đơn, nên customer_id được lặp lại trong orders.
  • Bảng chứa khoá ngoại gọi là bảng con, bảng được trỏ tới gọi là bảng cha.
  • Khác C# nơi Customer có thể giữ List<Order>, bảng cha không lưu danh sách: mỗi dòng con tự lưu khoá của cha.

Bốn bảng của cửa hàng nối với nhau như sau:

customers (no attributes) orders (no attributes) order_lines (no attributes) products (no attributes) đặt gồm nằm trong
Quan hệ giữa bốn bảng của cửa hàng

Thử ngay

SELECT order_id, customer_id, status
FROM orders
ORDER BY order_id;

Đoán trước khi chạy: khách số mấy có hai đơn hàng, và khách số 4 có đơn nào không?

Xem kết quả
ORDER_ID CUSTOMER_ID STATUS
1 1 PAID
2 1 NEW
3 2 PAID
4 3 CANCELLED

Khách số 1 (An) có hai đơn. Khách số 4 (Dũng) không có đơn nào. Muốn thấy tên khách thay vì mã, cần nối hai bảng bằng JOIN ở bài sau.

Lỗi hay gặp

Thêm đơn cho khách không tồn tại. INSERT thêm dòng, DELETE xoá dòng (học kỹ ở chương Thay đổi dữ liệu). Không có khách số 99, Oracle báo lỗi ORA-02291: không tìm thấy dòng cha.

-- SAI — lỗi: không có khách số 99
INSERT INTO orders (customer_id, order_date, status)
  VALUES (99, DATE '2025-03-01', 'NEW');
-- ĐÚNG — khách số 4 có thật
INSERT INTO orders (customer_id, order_date, status)
  VALUES (4, DATE '2025-03-01', 'NEW');

Xoá khách đang có đơn hàng. Nếu xoá được, các đơn đó sẽ trỏ tới một khách không còn tồn tại, nên Oracle chặn lại với lỗi ORA-02292: vẫn còn dòng con.

-- SAI — lỗi: khách số 1 vẫn còn đơn hàng
DELETE FROM customers WHERE customer_id = 1;
-- ĐÚNG — xoá dòng con trước (đơn 1 và 2 của An), rồi mới xoá khách
DELETE FROM order_lines WHERE order_id IN (1, 2);
DELETE FROM orders WHERE customer_id = 1;
DELETE FROM customers WHERE customer_id = 1;

Hai khối ĐÚNG ở trên sửa dữ liệu mẫu. Thử xong, chạy ROLLBACK; để huỷ (bài Transaction sẽ giải thích).

Tóm tắt

  • Khoá ngoại là cột trỏ tới khoá chính của bảng khác.
  • Database chặn giá trị khoá ngoại không tồn tại bên bảng cha.
  • Không xoá được dòng cha khi vẫn còn dòng con trỏ tới nó.
  • Một khách nhiều đơn, một đơn nhiều dòng hàng: đó là quan hệ một-nhiều.

Tự kiểm tra

0/3 câu
Câu 1

Bảng order_lines có cột product_id trỏ tới products. Thêm một dòng hàng với product_id = 50 trong khi chỉ có 5 sản phẩm. Chuyện gì xảy ra?

Câu 2

Trong quan hệ khách hàng và đơn hàng, cột khoá ngoại nằm ở bảng nào?

Câu 3

Vì sao orders chỉ lưu customer_id mà không lưu luôn tên và email của khách?

GROUP BY và HAVINGINNER JOIN

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt