Giới thiệu về Truy vấn trong MySQL
Database là thành phần quan trọng của nhiều trang web và ứng dụng, đồng thời là cốt lõi của cách dữ liệu được lưu trữ và trao đổi trên internet. Một trong những khía cạnh quan trọng nhất của quản lý database là thực hành truy xuất dữ liệu từ database , cho dù đó là trên cơ sở đặc biệt hay một phần của quy trình được mã hóa thành một ứng dụng. Có một số cách để lấy thông tin từ database , nhưng một trong những phương pháp được sử dụng phổ biến nhất là thực hiện thông qua việc gửi truy vấn thông qua dòng lệnh. Trong hệ quản trị database quan hệ, truy vấn là lệnh bất kỳ được sử dụng để truy xuất dữ liệu từ bảng. Trong Ngôn ngữ truy vấn có cấu trúc (SQL), các truy vấn hầu như luôn được thực hiện bằng cách sử dụng SELECT
.
Trong hướng dẫn này, ta sẽ thảo luận về cú pháp cơ bản của các truy vấn SQL cũng như một số hàm và toán tử được sử dụng phổ biến hơn. Ta cũng sẽ thực hành tạo các truy vấn SQL bằng cách sử dụng một số dữ liệu mẫu trong database MySQL.
MySQL là một hệ quản trị database quan hệ open-souce . Một trong những database SQL được triển khai rộng rãi nhất, MySQL ưu tiên tốc độ, độ tin cậy và khả năng sử dụng. Nó thường tuân theo tiêu chuẩn ANSI SQL, mặc dù có một số trường hợp MySQL thực hiện các hoạt động khác với tiêu chuẩn được công nhận.
Yêu cầu
Nói chung, các lệnh và khái niệm được trình bày trong hướng dẫn này được dùng trên bất kỳ hệ điều hành dựa trên Linux nào đang chạy bất kỳ phần mềm database SQL nào. Tuy nhiên, nó được viết riêng với server Ubuntu 18.04 chạy MySQL. Để cài đặt điều này, bạn cần những thứ sau:
- Máy Ubuntu 18.04 với user không phải root có quyền sudo. Điều này có thể được cài đặt bằng cách sử dụng hướng dẫn Cài đặt Server Ban đầu của ta cho Ubuntu 18.04 .
- MySQL đã được cài đặt trên máy. Hướng dẫn của ta về Cách cài đặt MySQL trên Ubuntu 18.04 có thể giúp bạn cài đặt điều này.
Với cài đặt này, ta có thể bắt đầu hướng dẫn.
Tạo database mẫu
Trước khi có thể bắt đầu thực hiện các truy vấn trong SQL, trước tiên ta sẽ tạo một database và một vài bảng, sau đó điền vào các bảng này một số dữ liệu mẫu. Điều này sẽ cho phép bạn có được một số kinh nghiệm thực tế khi bắt đầu thực hiện các truy vấn sau này.
Đối với database mẫu mà ta sẽ sử dụng trong suốt hướng dẫn này, hãy tưởng tượng tình huống sau:
Bạn và một số bạn bè của bạn đều tổ chức sinh nhật với nhau. Vào mỗi dịp, các thành viên của group đến playground bowling ở local , tham gia một giải đấu giao hữu, và sau đó mọi người đến nơi của bạn, nơi bạn chuẩn bị bữa ăn sinh nhật yêu thích của người đó.
Bây giờ truyền thống này đã diễn ra được một thời gian, bạn quyết định bắt đầu theo dõi các kỷ lục từ các giải đấu này. Ngoài ra, để lập kế hoạch bữa tối dễ dàng hơn, bạn quyết định tạo một bản ghi về sinh nhật của bạn bè và các món khai vị, món ăn kèm và món tráng miệng yêu thích của họ. Thay vì giữ thông tin này trong một sổ cái vật lý, bạn quyết định thực hiện các kỹ năng database của bạn bằng cách ghi lại nó trong database MySQL.
Để bắt đầu, hãy mở dấu nhắc MySQL với quyền là user MySQL gốc của bạn:
- sudo mysql
Lưu ý: Nếu bạn đã làm theo yêu cầu trong hướng dẫn Cài đặt MySQL trên Ubuntu 18.04 , bạn có thể đã cấu hình user gốc của bạn để xác thực bằng password . Trong trường hợp này, bạn sẽ kết nối với dấu nhắc MySQL bằng lệnh sau:
- mysql -u root -p
Tiếp theo, tạo database bằng lệnh:
- CREATE DATABASE `birthdays`;
Sau đó chọn database này bằng lệnh :
- USE birthdays;
Tiếp theo, tạo hai bảng trong database này. Ta sẽ sử dụng bảng đầu tiên để theo dõi profile của bạn bè bạn tại playground bowling. Lệnh sau sẽ tạo một bảng có tên là tourneys
với các cột cho name
của từng người bạn của bạn, số giải đấu mà họ đã giành được ( wins
), điểm số best
mọi thời đại của họ và loại giày bowling mà họ mang ( size
):
- CREATE TABLE tourneys (
- name varchar(30),
- wins real,
- best real,
- size real
- );
Khi bạn chạy CREATE TABLE
và điền nó với các tiêu đề cột, bạn sẽ nhận được kết quả sau:
OutputQuery OK, 0 rows affected (0.00 sec)
Điền vào bảng tourneys
với một số dữ liệu mẫu:
- INSERT INTO tourneys (name, wins, best, size)
- VALUES ('Dolly', '7', '245', '8.5'),
- ('Etta', '4', '283', '9'),
- ('Irma', '9', '266', '7'),
- ('Barbara', '2', '197', '7.5'),
- ('Gladys', '13', '273', '8');
Bạn sẽ nhận được một kết quả như sau:
OutputQuery OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0
Sau đó, tạo một bảng khác trong cùng một database mà ta sẽ sử dụng để lưu trữ thông tin về bữa ăn sinh nhật yêu thích của bạn bè bạn. Các lệnh sau đây tạo ra một bảng tên là dinners
với các cột cho name
của mỗi bạn bè, họ birthdate
, yêu thích của họ entree
, ưa thích của họ side
món ăn, và họ yêu thích dessert
:
- CREATE TABLE dinners (
- name varchar(30),
- birthdate date,
- entree varchar(30),
- side varchar(30),
- dessert varchar(30)
- );
Tương tự đối với bảng này, bạn sẽ nhận được phản hồi xác nhận lệnh đã chạy thành công:
OutputQuery OK, 0 rows affected (0.01 sec)
Cũng điền vào bảng này một số dữ liệu mẫu:
- INSERT INTO dinners (name, birthdate, entree, side, dessert)
- VALUES ('Dolly', '1946-01-19', 'steak', 'salad', 'cake'),
- ('Etta', '1938-01-25', 'chicken', 'fries', 'ice cream'),
- ('Irma', '1941-02-18', 'tofu', 'fries', 'cake'),
- ('Barbara', '1948-12-25', 'tofu', 'salad', 'ice cream'),
- ('Gladys', '1944-05-28', 'steak', 'fries', 'ice cream');
OutputQuery OK, 5 rows affected (0.00 sec) Records: 5 Duplicates: 0 Warnings: 0
Khi lệnh đó hoàn tất thành công, bạn đã hoàn tất việc cài đặt database của bạn . Tiếp theo, ta sẽ xem xét cấu trúc lệnh cơ bản của các truy vấn SELECT
.
Hiểu câu lệnh SELECT
Như đã đề cập trong phần giới thiệu, các truy vấn SQL hầu như luôn bắt đầu bằng SELECT
. SELECT
được sử dụng trong các truy vấn để chỉ định cột nào từ bảng sẽ được trả về trong tập kết quả. Các truy vấn hầu như luôn bao gồm FROM
, được sử dụng để chỉ định bảng mà câu lệnh sẽ truy vấn.
Nói chung, các truy vấn SQL tuân theo cú pháp sau:
- SELECT column_to_select FROM table_to_select WHERE certain_conditions_apply;
Ví dụ, câu lệnh sau sẽ trả về toàn bộ cột name
từ bảng dinners
:
- SELECT name FROM dinners;
Output+---------+ | name | +---------+ | Dolly | | Etta | | Irma | | Barbara | | Gladys | +---------+ 5 rows in set (0.00 sec)
Bạn có thể chọn nhiều cột từ cùng một bảng bằng cách tách tên của chúng bằng dấu phẩy, như sau:
- SELECT name, birthdate FROM dinners;
Output+---------+------------+ | name | birthdate | +---------+------------+ | Dolly | 1946-01-19 | | Etta | 1938-01-25 | | Irma | 1941-02-18 | | Barbara | 1948-12-25 | | Gladys | 1944-05-28 | +---------+------------+ 5 rows in set (0.00 sec)
Thay vì đặt tên cho một cột hoặc tập hợp các cột cụ thể, bạn có thể tuân theo toán tử SELECT
với dấu hoa thị ( *
) đóng role là trình giữ chỗ đại diện cho tất cả các cột trong bảng. Lệnh sau trả về mọi cột từ bảng tourneys
:
- SELECT * FROM tourneys;
Output+---------+------+------+------+ | name | wins | best | size | +---------+------+------+------+ | Dolly | 7 | 245 | 8.5 | | Etta | 4 | 283 | 9 | | Irma | 9 | 266 | 7 | | Barbara | 2 | 197 | 7.5 | | Gladys | 13 | 273 | 8 | +---------+------+------+------+ 5 rows in set (0.00 sec)
WHERE
được sử dụng trong các truy vấn để lọc các bản ghi đáp ứng một điều kiện cụ thể và bất kỳ hàng nào không đáp ứng điều kiện đó sẽ bị loại khỏi kết quả. WHERE
thường tuân theo cú pháp sau:
- . . . WHERE column_name comparison_operator value
Toán tử so sánh trong WHERE
xác định cách cột được chỉ định sẽ được so sánh với giá trị. Dưới đây là một số toán tử so sánh SQL phổ biến:
Nhà điều hành | Những gì nó làm |
---|---|
= | kiểm tra sự bình đẳng |
!= | kiểm tra sự bất bình đẳng |
< | kiểm tra cho ít hơn |
> | kiểm tra lớn hơn |
<= | kiểm tra nhỏ hơn hoặc bằng |
>= | các bài kiểm tra lớn hơn hoặc bằng |
BETWEEN | kiểm tra xem một giá trị có nằm trong một phạm vi nhất định hay không |
IN | kiểm tra xem giá trị của một hàng có nằm trong tập hợp các giá trị được chỉ định hay không |
EXISTS | kiểm tra xem các hàng có tồn tại hay không, với các điều kiện cụ thể |
LIKE | kiểm tra xem một giá trị có trùng với một chuỗi được chỉ định hay không |
IS NULL | kiểm tra giá trị NULL |
IS NOT NULL | kiểm tra tất cả các giá trị khác với NULL |
Ví dụ: nếu bạn muốn tìm cỡ giày của Irma, bạn có thể sử dụng truy vấn sau:
- SELECT size FROM tourneys WHERE name = 'Irma';
Output+------+ | size | +------+ | 7 | +------+ 1 row in set (0.00 sec)
SQL cho phép sử dụng các ký tự đại diện và những ký tự này đặc biệt tiện dụng khi được sử dụng trong WHERE
. Dấu phần trăm ( %
) đại diện cho không hoặc nhiều ký tự không xác định và dấu gạch dưới ( _
) đại diện cho một ký tự không xác định. Những điều này hữu ích nếu bạn đang cố gắng tìm một mục cụ thể trong một bảng, nhưng không chắc chắn về mục nhập đó chính xác là gì. Để minh họa, giả sử rằng bạn đã quên lời đề nghị yêu thích của một vài người bạn của bạn , nhưng bạn chắc chắn rằng lời đề nghị cụ thể này bắt đầu bằng chữ “t”. Bạn có thể tìm thấy tên của nó bằng cách chạy truy vấn sau:
- SELECT entree FROM dinners WHERE entree LIKE 't%';
Output+--------+ | entree | +--------+ | tofu | | tofu | +--------+ 2 rows in set (0.00 sec)
Dựa trên kết quả ở trên, ta thấy rằng món ăn mà ta đã quên là tofu
.
Có thể đôi khi bạn đang làm việc với database có các cột hoặc bảng có tên tương đối dài hoặc khó đọc. Trong những trường hợp này, bạn có thể làm cho những tên này dễ đọc hơn bằng cách tạo một alias với từ khóa AS
. Các alias được tạo bằng AS
là tạm thời và chỉ tồn tại trong thời gian truy vấn mà chúng được tạo:
- SELECT name AS n, birthdate AS b, dessert AS d FROM dinners;
Output+---------+------------+-----------+ | n | b | d | +---------+------------+-----------+ | Dolly | 1946-01-19 | cake | | Etta | 1938-01-25 | ice cream | | Irma | 1941-02-18 | cake | | Barbara | 1948-12-25 | ice cream | | Gladys | 1944-05-28 | ice cream | +---------+------------+-----------+ 5 rows in set (0.00 sec)
Ở đây, ta đã yêu cầu SQL hiển thị cột name
là n
, cột birthdate
là b
và cột dessert
là d
.
Các ví dụ mà ta đã xem qua cho đến thời điểm này bao gồm một số từ khóa và mệnh đề được sử dụng thường xuyên hơn trong các truy vấn SQL. Những điều này hữu ích cho các truy vấn cơ bản, nhưng chúng không hữu ích nếu bạn đang cố gắng thực hiện một phép tính hoặc lấy một giá trị vô hướng (một giá trị duy nhất, trái ngược với một tập hợp nhiều giá trị khác nhau) dựa trên dữ liệu . Đây là lúc các hàm tổng hợp phát huy tác dụng.
Chức năng tổng hợp
Thông thường, khi làm việc với dữ liệu, bạn không nhất thiết muốn xem dữ liệu đó. Đúng hơn, bạn muốn thông tin về dữ liệu. Cú pháp SQL bao gồm một số hàm cho phép bạn diễn giải hoặc chạy các phép tính trên dữ liệu của bạn chỉ bằng cách đưa ra một truy vấn SELECT
. Chúng được gọi là các hàm tổng hợp .
Hàm COUNT
đếm và trả về số hàng phù hợp với một tiêu chí nhất định. Ví dụ: nếu bạn muốn biết có bao nhiêu người bạn của bạn thích đậu phụ cho bữa tiệc sinh nhật của họ, bạn có thể đưa ra truy vấn sau:
- SELECT COUNT(entree) FROM dinners WHERE entree = 'tofu';
Output+---------------+ | COUNT(entree) | +---------------+ | 2 | +---------------+ 1 row in set (0.00 sec)
Hàm AVG
trả về giá trị trung bình (trung bình) của một cột. Sử dụng bảng ví dụ của ta , bạn có thể tìm thấy điểm tốt nhất trung bình giữa bạn bè của bạn với truy vấn này:
- SELECT AVG(best) FROM tourneys;
Output+-----------+ | AVG(best) | +-----------+ | 252.8 | +-----------+ 1 row in set (0.00 sec)
SUM
được sử dụng để tìm tổng cộng của một cột nhất định. Ví dụ: nếu bạn muốn xem bạn và bạn bè của bạn đã chơi bao nhiêu trận trong những năm qua, bạn có thể chạy truy vấn sau:
- SELECT SUM(wins) FROM tourneys;
Output+-----------+ | SUM(wins) | +-----------+ | 35 | +-----------+ 1 row in set (0.00 sec)
Lưu ý các hàm AVG
và SUM
sẽ chỉ hoạt động chính xác khi được sử dụng với dữ liệu số. Nếu bạn cố gắng sử dụng chúng trên dữ liệu không phải số, nó sẽ dẫn đến lỗi hoặc chỉ là 0
, tùy thuộc vào RDBMS bạn đang sử dụng:
- SELECT SUM(entree) FROM dinners;
Output+-------------+ | SUM(entree) | +-------------+ | 0 | +-------------+ 1 row in set, 5 warnings (0.00 sec)
MIN
được sử dụng để tìm giá trị nhỏ nhất trong một cột được chỉ định. Bạn có thể sử dụng truy vấn này để xem kỷ lục chơi bowling tổng thể tồi tệ nhất cho đến nay là bao nhiêu (về số trận thắng):
- SELECT MIN(wins) FROM tourneys;
Output+-----------+ | MIN(wins) | +-----------+ | 2 | +-----------+ 1 row in set (0.00 sec)
Tương tự, MAX
được sử dụng để tìm giá trị số lớn nhất trong một cột nhất định. Truy vấn sau đây sẽ hiển thị thành tích bowling tổng thể tốt nhất:
- SELECT MAX(wins) FROM tourneys;
Output+-----------+ | MAX(wins) | +-----------+ | 13 | +-----------+ 1 row in set (0.00 sec)
Không giống như SUM
và AVG
, hàm MIN
và MAX
được dùng cho cả kiểu dữ liệu số và chữ cái. Khi chạy trên cột chứa giá trị chuỗi, hàm MIN
sẽ hiển thị giá trị đầu tiên theo thứ tự bảng chữ cái:
- SELECT MIN(name) FROM dinners;
Output+-----------+ | MIN(name) | +-----------+ | Barbara | +-----------+ 1 row in set (0.00 sec)
Tương tự như vậy, khi chạy trên cột chứa giá trị chuỗi, hàm MAX
sẽ hiển thị giá trị cuối cùng theo thứ tự bảng chữ cái:
- SELECT MAX(name) FROM dinners;
Output+-----------+ | MAX(name) | +-----------+ | Irma | +-----------+ 1 row in set (0.00 sec)
Hàm tổng hợp có nhiều công dụng ngoài những gì được mô tả trong phần này. Chúng đặc biệt hữu ích khi được sử dụng với mệnh đề GROUP BY
, được đề cập trong phần tiếp theo cùng với một số mệnh đề truy vấn khác ảnh hưởng đến cách sắp xếp các tập kết quả.
Thao tác kết quả truy vấn
Ngoài WHERE
đề FROM
và WHERE
, có một số mệnh đề khác được sử dụng để điều khiển kết quả của một truy vấn SELECT
. Trong phần này, ta sẽ giải thích và cung cấp các ví dụ cho một số mệnh đề truy vấn thường được sử dụng hơn.
Một trong những mệnh đề truy vấn được sử dụng thường xuyên nhất, ngoài FROM
và WHERE
, là mệnh đề GROUP BY
. Nó thường được sử dụng khi bạn đang thực hiện một hàm tổng hợp trên một cột, nhưng liên quan đến việc khớp các giá trị trong một cột khác.
Ví dụ: giả sử bạn muốn biết có bao nhiêu người bạn của bạn thích mỗi trong số ba lời mời mà bạn thực hiện. Bạn có thể tìm thấy thông tin này với truy vấn sau:
- SELECT COUNT(name), entree FROM dinners GROUP BY entree;
Output+-------------+---------+ | COUNT(name) | entree | +-------------+---------+ | 1 | chicken | | 2 | steak | | 2 | tofu | +-------------+---------+ 3 rows in set (0.00 sec)
Mệnh đề ORDER BY
được sử dụng để sắp xếp kết quả truy vấn. Theo mặc định, các giá trị số được sắp xếp theo thứ tự tăng dần và các giá trị văn bản được sắp xếp theo thứ tự bảng chữ cái. Để minh họa, truy vấn sau liệt kê các cột name
và birthdate
, nhưng sắp xếp kết quả theo ngày sinh:
- SELECT name, birthdate FROM dinners ORDER BY birthdate;
Output+---------+------------+ | name | birthdate | +---------+------------+ | Etta | 1938-01-25 | | Irma | 1941-02-18 | | Gladys | 1944-05-28 | | Dolly | 1946-01-19 | | Barbara | 1948-12-25 | +---------+------------+ 5 rows in set (0.00 sec)
Lưu ý hành vi mặc định của ORDER BY
là sắp xếp tập hợp kết quả theo thứ tự tăng dần. Để đảo ngược điều này và sắp xếp tập hợp kết quả theo thứ tự giảm dần, hãy đóng truy vấn bằng DESC
:
- SELECT name, birthdate FROM dinners ORDER BY birthdate DESC;
Output+---------+------------+ | name | birthdate | +---------+------------+ | Barbara | 1948-12-25 | | Dolly | 1946-01-19 | | Gladys | 1944-05-28 | | Irma | 1941-02-18 | | Etta | 1938-01-25 | +---------+------------+ 5 rows in set (0.00 sec)
Như đã đề cập trước đây, WHERE
được sử dụng để lọc kết quả dựa trên các điều kiện cụ thể. Tuy nhiên, nếu bạn sử dụng WHERE
với một hàm tổng hợp, nó sẽ trả về lỗi, như trường hợp với nỗ lực sau để tìm mặt nào là yêu thích của ít nhất ba người bạn của bạn:
- SELECT COUNT(name), side FROM dinners WHERE COUNT(name) >= 3;
OutputERROR 1111 (HY000): Invalid use of group function
Mệnh đề HAVING
đã được thêm vào SQL để cung cấp chức năng tương tự như WHERE
trong khi cũng tương thích với các hàm tổng hợp. Thật hữu ích khi nghĩ về sự khác biệt giữa hai mệnh đề này là WHERE
áp dụng cho các bản ghi cá nhân, trong khi HAVING
áp dụng cho các bản ghi group . Vì vậy, bất kỳ khi nào bạn đưa ra mệnh đề HAVING
, mệnh đề GROUP BY
cũng phải có mặt.
Ví dụ sau là một nỗ lực khác để tìm món ăn phụ nào là món yêu thích của ít nhất ba người bạn của bạn, mặc dù ví dụ này sẽ trả về kết quả không có lỗi:
- SELECT COUNT(name), side FROM dinners GROUP BY side HAVING COUNT(name) >= 3;
Output+-------------+-------+ | COUNT(name) | side | +-------------+-------+ | 3 | fries | +-------------+-------+ 1 row in set (0.00 sec)
Hàm tổng hợp rất hữu ích để tóm tắt kết quả của một cột cụ thể trong một bảng nhất định. Tuy nhiên, có nhiều trường hợp cần truy vấn nội dung của nhiều hơn một bảng. Ta sẽ xem xét một số cách bạn có thể thực hiện việc này trong phần tiếp theo.
Truy vấn nhiều bảng
Thường xuyên hơn không, một database chứa nhiều bảng, mỗi bảng chứa các tập dữ liệu khác nhau. SQL cung cấp một số cách khác nhau để chạy một truy vấn trên nhiều bảng.
Mệnh đề JOIN
được dùng để kết hợp các hàng từ hai hoặc nhiều bảng trong một kết quả truy vấn. Nó thực hiện điều này bằng cách tìm một cột liên quan giữa các bảng và sắp xếp kết quả một cách thích hợp trong kết quả .
SELECT
bao gồm một mệnh đề JOIN
thường tuân theo cú pháp sau:
- SELECT table1.column1, table2.column2
- FROM table1
- JOIN table2 ON table1.related_column=table2.related_column;
Lưu ý vì mệnh đề JOIN
so sánh nội dung của nhiều hơn một bảng, ví dụ trước chỉ định bảng để chọn từng cột bằng cách đặt trước tên của cột với tên của bảng và dấu chấm. Bạn có thể chỉ định bảng nào nên chọn cột như thế này cho bất kỳ truy vấn nào, mặc dù không cần thiết khi chọn từ một bảng, như ta đã thực hiện trong các phần trước. Hãy xem qua một ví dụ bằng cách sử dụng dữ liệu mẫu của ta .
Hãy tưởng tượng rằng bạn muốn mua cho mỗi người bạn của bạn một đôi giày bowling làm quà sinh nhật. Vì thông tin về ngày sinh và kích cỡ giày của bạn bè được lưu trữ trong các bảng riêng biệt, bạn có thể truy vấn cả hai bảng riêng biệt sau đó so sánh kết quả từ mỗi bảng. Tuy nhiên, với mệnh đề JOIN
, bạn có thể tìm thấy tất cả thông tin mình muốn chỉ với một truy vấn:
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- JOIN dinners ON tourneys.name=dinners.name;
Output+---------+------+------------+ | name | size | birthdate | +---------+------+------------+ | Dolly | 8.5 | 1946-01-19 | | Etta | 9 | 1938-01-25 | | Irma | 7 | 1941-02-18 | | Barbara | 7.5 | 1948-12-25 | | Gladys | 8 | 1944-05-28 | +---------+------+------------+ 5 rows in set (0.00 sec)
Mệnh đề JOIN
được sử dụng trong ví dụ này, không có bất kỳ đối số nào khác, là một mệnh đề JOIN
bên trong . Điều này nghĩa là nó chọn tất cả các bản ghi có giá trị phù hợp trong cả hai bảng và in chúng vào tập kết quả, trong khi bất kỳ bản ghi nào không phù hợp sẽ bị loại trừ. Để minh họa cho ý tưởng này, hãy thêm một hàng mới vào mỗi bảng không có mục nhập tương ứng trong bảng kia:
- INSERT INTO tourneys (name, wins, best, size)
- VALUES ('Bettye', '0', '193', '9');
- INSERT INTO dinners (name, birthdate, entree, side, dessert)
- VALUES ('Lesley', '1946-05-02', 'steak', 'salad', 'ice cream');
Sau đó, chạy lại SELECT
trước đó với mệnh đề JOIN
:
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- JOIN dinners ON tourneys.name=dinners.name;
Output+---------+------+------------+ | name | size | birthdate | +---------+------+------------+ | Dolly | 8.5 | 1946-01-19 | | Etta | 9 | 1938-01-25 | | Irma | 7 | 1941-02-18 | | Barbara | 7.5 | 1948-12-25 | | Gladys | 8 | 1944-05-28 | +---------+------+------------+ 5 rows in set (0.00 sec)
Lưu ý , bởi vì bảng tourneys
không có mục nhập cho Lesley và bảng dinners
không có mục nhập cho Bettye, các bản ghi đó không có trong kết quả này.
Tuy nhiên, có thể trả về tất cả các bản ghi từ một trong các bảng bằng mệnh đề JOIN
bên ngoài . Trong MySQL, mệnh đề JOIN
được viết dưới dạng LEFT JOIN
hoặc RIGHT JOIN
.
Mệnh đề LEFT JOIN
trả về tất cả các bản ghi từ bảng “bên trái” và chỉ các bản ghi phù hợp từ bảng bên phải. Trong ngữ cảnh của các phép nối bên ngoài, bảng bên trái là bảng được tham chiếu bởi mệnh đề FROM
và bảng bên phải là bất kỳ bảng nào khác được tham chiếu sau câu lệnh JOIN
.
Chạy lại truy vấn trước đó, nhưng lần này sử dụng mệnh đề LEFT JOIN
:
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- LEFT JOIN dinners ON tourneys.name=dinners.name;
Lệnh này sẽ trả về mọi bản ghi từ bảng bên trái (trong trường hợp này là tourneys
) ngay cả khi nó không có bản ghi tương ứng trong bảng bên phải. Bất kỳ lúc nào không có bản ghi phù hợp từ bảng bên phải, nó được trả về dưới dạng NULL
hoặc chỉ là giá trị trống, tùy thuộc vào RDBMS của bạn:
Output+---------+------+------------+ | name | size | birthdate | +---------+------+------------+ | Dolly | 8.5 | 1946-01-19 | | Etta | 9 | 1938-01-25 | | Irma | 7 | 1941-02-18 | | Barbara | 7.5 | 1948-12-25 | | Gladys | 8 | 1944-05-28 | | Bettye | 9 | NULL | +---------+------+------------+ 6 rows in set (0.00 sec)
Bây giờ chạy lại truy vấn, lần này với mệnh đề RIGHT JOIN
:
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- RIGHT JOIN dinners ON tourneys.name=dinners.name;
Thao tác này sẽ trả về tất cả các bản ghi từ bảng bên phải ( dinners
). Vì ngày sinh của Lesley được ghi trong bảng bên phải, nhưng không có hàng tương ứng cho cô ấy trong bảng bên trái, các cột name
và size
sẽ trả về dưới dạng giá trị NULL
trong hàng đó:
Output+---------+------+------------+ | name | size | birthdate | +---------+------+------------+ | Dolly | 8.5 | 1946-01-19 | | Etta | 9 | 1938-01-25 | | Irma | 7 | 1941-02-18 | | Barbara | 7.5 | 1948-12-25 | | Gladys | 8 | 1944-05-28 | | NULL | NULL | 1946-05-02 | +---------+------+------------+ 6 rows in set (0.00 sec)
Lưu ý phép nối trái và phải có thể được viết dưới dạng LEFT OUTER JOIN
hoặc RIGHT OUTER JOIN
, mặc dù phần OUTER
của mệnh đề được ngụ ý. Tương tự như vậy, chỉ định INNER JOIN
sẽ tạo ra kết quả tương tự như chỉ viết JOIN
.
Để thay thế cho việc sử dụng JOIN
để truy vấn bản ghi từ nhiều bảng, bạn có thể sử dụng mệnh đề UNION
.
Toán tử UNION
hoạt động hơi khác so với mệnh đề JOIN
: thay vì in kết quả từ nhiều bảng dưới dạng cột duy nhất bằng cách sử dụng một SELECT
, UNION
kết hợp kết quả của hai SELECT
thành một cột duy nhất.
Để minh họa, hãy chạy truy vấn sau:
- SELECT name FROM tourneys UNION SELECT name FROM dinners;
Truy vấn này sẽ xóa mọi mục nhập trùng lặp, đây là hành vi mặc định của UNION
tử UNION
:
Output+---------+ | name | +---------+ | Dolly | | Etta | | Irma | | Barbara | | Gladys | | Bettye | | Lesley | +---------+ 7 rows in set (0.00 sec)
Để trả lại tất cả các mục nhập (bao gồm cả các mục trùng lặp), hãy sử dụng UNION ALL
:
- SELECT name FROM tourneys UNION ALL SELECT name FROM dinners;
Output+---------+ | name | +---------+ | Dolly | | Etta | | Irma | | Barbara | | Gladys | | Bettye | | Dolly | | Etta | | Irma | | Barbara | | Gladys | | Lesley | +---------+ 12 rows in set (0.00 sec)
Tên và số cột trong bảng kết quả phản ánh tên và số cột được truy vấn bởi SELECT
đầu tiên. Lưu ý khi sử dụng UNION
để truy vấn nhiều cột từ nhiều bảng, mỗi SELECT
phải truy vấn cùng một số cột, các cột tương ứng phải có kiểu dữ liệu tương tự và các cột trong mỗi SELECT
phải theo cùng một thứ tự. Ví dụ sau cho thấy điều gì có thể dẫn đến nếu bạn sử dụng mệnh đề UNION
trên hai SELECT
truy vấn một số cột khác nhau:
- SELECT name FROM dinners UNION SELECT name, wins FROM tourneys;
OutputERROR 1222 (21000): The used SELECT statements have a different number of columns
Một cách khác để truy vấn nhiều bảng là sử dụng các truy vấn con . Truy vấn con ( còn gọi là truy vấn nội bộ hoặc truy vấn lồng nhau ) là các truy vấn nằm trong một truy vấn khác. Những điều này hữu ích trong trường hợp bạn đang cố gắng lọc kết quả của một truy vấn so với kết quả của một hàm tổng hợp riêng biệt.
Để minh họa cho ý tưởng này, giả sử bạn muốn biết ai trong số những người bạn của bạn đã thắng nhiều trận hơn Barbara. Thay vì truy vấn xem Barbara đã thắng bao nhiêu trận rồi chạy một truy vấn khác để xem ai đã thắng nhiều trận hơn thế, bạn có thể tính toán cả hai chỉ với một truy vấn:
- SELECT name, wins FROM tourneys
- WHERE wins > (
- SELECT wins FROM tourneys WHERE name = 'Barbara'
- );
Output+--------+------+ | name | wins | +--------+------+ | Dolly | 7 | | Etta | 4 | | Irma | 9 | | Gladys | 13 | +--------+------+ 4 rows in set (0.00 sec)
Truy vấn con trong câu lệnh này chỉ được chạy một lần; nó chỉ cần tìm giá trị từ cột wins
ở cùng hàng với Barbara
trong cột name
và dữ liệu được trả về bởi truy vấn con và truy vấn bên ngoài là độc lập với nhau. Tuy nhiên, có những trường hợp, trong đó truy vấn bên ngoài trước tiên phải đọc mọi hàng trong bảng và so sánh các giá trị đó với dữ liệu do truy vấn con trả về để trả về dữ liệu mong muốn. Trong trường hợp này, truy vấn con được gọi là truy vấn con tương quan .
Câu lệnh sau đây là một ví dụ về một truy vấn con tương quan. Truy vấn này nhằm tìm ra người bạn nào của bạn đã thắng nhiều trò chơi hơn mức trung bình của những người có cùng cỡ giày:
- SELECT name, size FROM tourneys AS t
- WHERE wins > (
- SELECT AVG(wins) FROM tourneys WHERE size = t.size
- );
Để truy vấn hoàn thành, trước tiên nó phải thu thập các cột name
và size
từ truy vấn bên ngoài. Sau đó, nó so sánh từng hàng từ tập hợp kết quả đó với kết quả của truy vấn bên trong, xác định số trận thắng trung bình cho các cá nhân có cỡ giày giống nhau. Vì bạn chỉ có hai người bạn có cùng cỡ giày nên chỉ có thể có một hàng trong tập kết quả:
Output+------+------+ | name | size | +------+------+ | Etta | 9 | +------+------+ 1 row in set (0.00 sec)
Như đã đề cập trước đó, truy vấn con được dùng để truy vấn kết quả từ nhiều bảng. Để minh họa điều này bằng một ví dụ cuối cùng, giả sử bạn muốn tổ chức một bữa tối bất ngờ cho người ném bóng giỏi nhất mọi thời đại của group . Bạn có thể tìm thấy bạn bè nào của bạn có thành tích chơi bowling tốt nhất và trả lại bữa ăn yêu thích của họ bằng truy vấn sau:
- SELECT name, entree, side, dessert
- FROM dinners
- WHERE name = (SELECT name FROM tourneys
- WHERE wins = (SELECT MAX(wins) FROM tourneys));
Output+--------+--------+-------+-----------+ | name | entree | side | dessert | +--------+--------+-------+-----------+ | Gladys | steak | fries | ice cream | +--------+--------+-------+-----------+ 1 row in set (0.00 sec)
Lưu ý câu lệnh này không chỉ bao gồm một truy vấn con mà còn chứa một truy vấn con bên trong truy vấn con đó.
Kết luận
Phát hành truy vấn là một trong những tác vụ thường được thực hiện nhất trong lĩnh vực quản lý database . Có một số công cụ quản trị database , chẳng hạn như phpMyAdmin hoặc pgAdmin , cho phép bạn thực hiện các truy vấn và trực quan hóa kết quả, nhưng việc phát hành các SELECT
từ dòng lệnh vẫn là một quy trình làm việc được thực hành rộng rãi cũng có thể cung cấp cho bạn khả năng kiểm soát tốt hơn.
Nếu bạn mới làm việc với SQL, ta khuyến khích bạn sử dụng Trang Cheat SQL của ta làm tài liệu tham khảo và xem lại tài liệu MySQL chính thức . Ngoài ra, nếu bạn muốn tìm hiểu thêm về SQL và database quan hệ, các hướng dẫn sau đây có thể bạn quan tâm:
- Hiểu database SQL và NoSQL và các mô hình database khác nhau
- Cách tạo một cụm MySQL nhiều nút trên Ubuntu 18.04
- Cách đặt lại password root MySQL hoặc MariaDB của bạn trên Ubuntu 18.04
Các tin liên quan
Cách cài đặt MySQL mới nhất trên Debian 92018-09-05
Cách đặt lại mật khẩu gốc MySQL hoặc MariaDB của bạn trên Ubuntu 18.04
2018-09-04
Cách tạo một cụm MySQL nhiều node trên Ubuntu 18.04
2018-07-26
Cách cài đặt MySQL mới nhất trên Ubuntu 18.04
2018-07-12
Cách di chuyển thư mục dữ liệu MySQL đến vị trí mới trên Ubuntu 18.04
2018-07-06
Cách triển khai ứng dụng Elixir-Phoenix với MySQL trên Ubuntu 16.04
2018-05-07
Cách sử dụng ProxySQL làm Bộ cân bằng tải cho MySQL trên Ubuntu 16.04
2018-01-08
Cách backup database MySQL vào lưu trữ đối tượng với Percona trên Ubuntu 16.04
2017-10-19
Cách cài đặt Lighttpd với MySQL và PHP trên FreeBSD 11.0
2017-09-18
Cách cấu hình backup MySQL với Percona XtraBackup trên Ubuntu 16.04
2017-08-30