Truy vấn con để giải quyết truy vấn

Một truy vấn con được xác định tốt nhất là một truy vấn trong một truy vấn. Truy vấn con cho phép bạn viết các truy vấn chọn hàng dữ liệu cho các tiêu chí thực sự được phát triển trong khi truy vấn đang thực hiện tại thời điểm chạy. Chính thức hơn, đó là việc sử dụng một câu lệnh SELECT bên trong một trong các mệnh đề của một câu lệnh SELECT khác. Trên thực tế, một truy vấn con có thể được chứa bên trong một truy vấn con khác, bên trong một truy vấn con khác, v.v. Một truy vấn con cũng có thể được lồng vào bên trong các câu lệnh INSERT, UPDATE và DELETE. Truy vấn con phải được đặt trong dấu ngoặc đơn.

Một truy vấn con có thể được sử dụng ở bất kỳ nơi nào mà một biểu thức được phép miễn là nó trả về một giá trị duy nhất. Điều này có nghĩa là một truy vấn con trả về một giá trị duy nhất cũng có thể được liệt kê như một đối tượng trong danh sách mệnh đề FROM. Đây được gọi là dạng xem nội tuyến vì khi truy vấn con được sử dụng như một phần của mệnh đề FROM, nó được coi như một bảng hoặc dạng xem ảo. Truy vấn con có thể được đặt trong mệnh đề FROM, mệnh đề WHERE hoặc mệnh đề HAVING của truy vấn chính.

Oracle cho phép lồng tối đa 255 cấp truy vấn con trong mệnh đề WHERE. Không có giới hạn cho các truy vấn con lồng nhau được thể hiện trong mệnh đề FROM, trong thực tế, giới hạn 255 cấp không thực sự là một giới hạn vì hiếm khi gặp phải các truy vấn con lồng nhau vượt quá ba hoặc bốn cấp.

Câu lệnh SELECT truy vấn con rất giống với câu lệnh SELECT được sử dụng để bắt đầu một truy vấn thông thường hoặc truy vấn bên ngoài. Cú pháp hoàn chỉnh của truy vấn con là:

( SELECT [DISTINCT] subquery_select_parameter
  FROM {table_name | view_name}
               {table_name | view_name} ...
  [WHERE search_conditions]
  [GROUP BY column_name [,column_name ] ...]
  [HAVING search_conditions] )

Các loại truy vấn con

Single Row Sub Query: Truy vấn phụ trả về kết quả hàng đơn. Chúng đánh dấu việc sử dụng các toán tử so sánh hàng đơn, khi được sử dụng trong điều kiện WHERE.

Multiple row sub query: Truy vấn phụ trả về đầu ra nhiều hàng. Họ sử dụng nhiều toán tử so sánh hàng như IN, ANY, ALL. Cũng có thể có các truy vấn phụ trả về nhiều cột.

Correlated Sub Query: Truy vấn con có liên quan phụ thuộc vào dữ liệu được cung cấp bởi truy vấn bên ngoài. Loại truy vấn con này cũng bao gồm các truy vấn con sử dụng toán tử EXISTS để kiểm tra sự tồn tại của các hàng dữ liệu thỏa mãn các tiêu chí đã chỉ định.

Truy vấn phụ một hàng

Truy vấn con một hàng được sử dụng khi kết quả của truy vấn bên ngoài dựa trên một giá trị duy nhất, không xác định. Mặc dù loại truy vấn này chính thức được gọi là "một hàng", tên này ngụ ý rằng truy vấn trả về nhiều cột - nhưng chỉ một hàng kết quả. Tuy nhiên, truy vấn con một hàng chỉ có thể trả về một hàng kết quả chỉ gồm một cột cho truy vấn bên ngoài.

Trong truy vấn SELECT bên dưới, SQL bên trong chỉ trả về một hàng tức là mức lương tối thiểu cho công ty. Đến lượt nó, nó sử dụng giá trị này để so sánh mức lương của tất cả các nhân viên và chỉ hiển thị những người có mức lương bằng mức lương tối thiểu.

SELECT first_name, salary, department_id
FROM employees
WHERE salary = (SELECT MIN (salary) 
		FROM employees);

Mệnh đề HAVING được sử dụng khi kết quả nhóm của một truy vấn cần được hạn chế dựa trên một số điều kiện. Nếu kết quả của một truy vấn con phải được so sánh với một hàm nhóm, bạn phải lồng truy vấn bên trong vào mệnh đề HAVING của truy vấn bên ngoài.

SELECT department_id, MIN (salary)
FROM employees
GROUP BY department_id
HAVING MIN (salary)  < (SELECT AVG (salary) FROM employees)

Truy vấn phụ nhiều hàng

Truy vấn con nhiều hàng là các truy vấn lồng nhau có thể trả về nhiều hơn một hàng kết quả cho truy vấn chính. Truy vấn con nhiều hàng được sử dụng phổ biến nhất trong mệnh đề WHERE và HAVING. Vì nó trả về nhiều hàng nên nó phải được xử lý bởi các toán tử so sánh đã đặt (IN, ALL, ANY). Mặc dù toán tử IN có cùng ý nghĩa như đã thảo luận trong chương trước, nhưng toán tử BẤT KỲ so sánh một giá trị được chỉ định với mỗi giá trị được trả về bởi truy vấn con ALL so sánh một giá trị với mọi giá trị được trả về bởi một truy vấn phụ.

Truy vấn bên dưới hiển thị lỗi khi truy vấn con một hàng trả về nhiều hàng.

SELECT	first_name, department_id
FROM employees
WHERE department_id = (SELECT department_id FROM employees WHERE LOCATION_ID = 100)
department_id = (select
               *
ERROR at line 4:
ORA-01427: single-row subquery returns more than one row

Cách sử dụng nhiều toán tử Hàng

  • [> TẤT CẢ] Nhiều hơn giá trị cao nhất mà truy vấn con trả về

  • [<TẤT CẢ] Nhỏ hơn giá trị thấp nhất mà truy vấn con trả về

  • [<ANY] Nhỏ hơn giá trị cao nhất mà truy vấn con trả về

  • [> ANY] Nhiều hơn giá trị thấp nhất mà truy vấn con trả về

  • [= ANY] Bằng bất kỳ giá trị nào được trả về bởi truy vấn con (giống như IN)

SQL trên có thể được viết lại bằng cách sử dụng toán tử IN như dưới đây.

SELECT	first_name, department_id
FROM employees
WHERE department_id IN (SELECT department_id
                   	    FROM departments
                   	    WHERE LOCATION_ID = 100)

Lưu ý trong truy vấn trên, IN khớp với id bộ phận được trả về từ truy vấn phụ, so sánh với id bộ phận trong truy vấn chính và trả về tên của nhân viên thỏa mãn điều kiện.

Một phép nối sẽ là giải pháp tốt hơn cho truy vấn trên, nhưng với mục đích minh họa, truy vấn phụ đã được sử dụng trong đó.

Truy vấn phụ có liên quan

Trái ngược với truy vấn con thông thường, trong đó truy vấn bên ngoài phụ thuộc vào các giá trị được cung cấp bởi truy vấn bên trong, truy vấn con tương quan là truy vấn trong đó truy vấn bên trong phụ thuộc vào các giá trị được cung cấp bởi truy vấn bên ngoài. Điều này có nghĩa là trong một truy vấn con có tương quan, truy vấn bên trong được thực thi lặp đi lặp lại, một lần cho mỗi hàng có thể được chọn bởi truy vấn bên ngoài.

Các truy vấn con có liên quan có thể tạo ra các bảng kết quả trả lời các câu hỏi quản lý phức tạp.

Hãy xem xét truy vấn SELECT bên dưới. Không giống như các truy vấn con được xem xét trước đây, truy vấn con trong câu lệnh SELECT này không thể được giải quyết độc lập với truy vấn chính. Lưu ý rằng truy vấn bên ngoài chỉ định rằng các hàng được chọn từ bảng nhân viên với tên bí danh là e1. Truy vấn bên trong so sánh cột số bộ phận nhân viên (DepartmentNumber) của bảng nhân viên có bí danh e2 với cùng một cột cho tên bảng bí danh e1.

SELECT EMPLOYEE_ID, salary, department_id
FROM   employees E
WHERE salary > (SELECT AVG(salary)
                FROM   EMP T
                WHERE E.department_id = T.department_id)

Truy vấn nhiều cột phụ

Truy vấn con nhiều cột trả về nhiều hơn một cột cho truy vấn bên ngoài và có thể được liệt kê trong mệnh đề FROM, WHERE hoặc HAVING của truy vấn bên ngoài. Ví dụ: truy vấn dưới đây hiển thị chi tiết lịch sử của nhân viên cho những người có mức lương hiện tại nằm trong khoảng 1000 và 2000 và đang làm việc ở bộ phận 10 hoặc 20.

SELECT first_name, job_id, salary
FROM emp_history
WHERE (salary, department_id) in (SELECT salary, department_id
				  FROM employees
 				  WHERE salary BETWEEN 1000 and 2000 
				  AND department_id BETWEEN 10 and 20)
ORDER BY first_name;

Khi một truy vấn con nhiều cột được sử dụng trong mệnh đề FROM của truy vấn bên ngoài, nó sẽ tạo ra một bảng tạm thời có thể được tham chiếu bởi các mệnh đề khác của truy vấn bên ngoài. Bảng tạm thời này được gọi chính thức hơn là một dạng xem nội tuyến. Kết quả của truy vấn con được xử lý giống như bất kỳ bảng nào khác trong mệnh đề FROM. Nếu bảng tạm thời chứa dữ liệu được nhóm lại, thì các tập hợp con được nhóm lại được coi là các hàng dữ liệu riêng biệt trong bảng. Xem xét mệnh đề FROM trong truy vấn dưới đây. Dạng xem nội tuyến được tạo bởi truy vấn con là nguồn dữ liệu cho truy vấn chính.

SELECT * 
FROM (SELECT salary, department_id
	FROM employees
 	WHERE salary BETWEEN 1000 and 2000);