Bạn sẽ không viết một ứng dụng có hàm dài 200 dòng. Bạn sẽ phân rã các hàm dài đó thành các hàm nhỏ hơn, mỗi hàm có một trách nhiệm được xác định rõ ràng.
Tại sao viết SQL của bạn như vậy?
Phân rã các truy vấn của bạn, giống như bạn phân rã các chức năng của mình. Điều này làm cho chúng ngắn hơn, đơn giản hơn, dễ hiểu hơn , dễ kiểm tra hơn, dễ cấu trúc lại. Và nó cho phép bạn thêm "miếng chêm" vào giữa chúng và "lớp bọc" xung quanh chúng, giống như bạn làm trong mã thủ tục.
Làm thế nào để bạn làm điều này? Bằng cách biến mỗi điều quan trọng mà một truy vấn thực hiện thành một chế độ xem. Sau đó, bạn soạn các truy vấn phức tạp hơn từ các khung nhìn đơn giản này, cũng giống như bạn soạn các hàm phức tạp hơn từ các hàm nguyên thủy hơn.
Và điều tuyệt vời là, đối với hầu hết các thành phần chế độ xem, bạn sẽ nhận được chính xác hiệu suất tương tự từ RDBMS của mình. (Đối với một số bạn thì không; vậy thì sao? Tối ưu hóa sớm là gốc rễ của mọi điều xấu. Trước tiên hãy viết mã chính xác, sau đó tối ưu hóa nếu bạn cần.)
Đây là một ví dụ về việc sử dụng một số dạng xem để phân tách một truy vấn phức tạp.
Trong ví dụ này, vì mỗi chế độ xem chỉ thêm một phép biến đổi, mỗi phép biến đổi có thể được kiểm tra độc lập để tìm lỗi và việc kiểm tra rất đơn giản.
Đây là bảng cơ sở trong ví dụ:
create table month_value(
eid int not null, month int, year int, value int );
Bảng này thiếu sót, vì nó sử dụng hai cột, tháng và năm, để đại diện cho một số liệu, một tháng tuyệt đối. Đây là đặc điểm kỹ thuật của chúng tôi cho cột mới được tính toán:
Chúng tôi sẽ thực hiện điều đó dưới dạng một phép biến đổi tuyến tính, sao cho nó sắp xếp giống như (năm, tháng) và sao cho bất kỳ bộ (năm, tháng) nào đều có một giá trị duy nhất và tất cả các giá trị đều liên tiếp:
create view cm_absolute_month as
select *, year * 12 + month as absolute_month from month_value;
Bây giờ những gì chúng ta phải kiểm tra đã có trong thông số kỹ thuật của chúng ta, cụ thể là đối với bất kỳ tuple (năm, tháng) nào, chỉ có một và chỉ một (tuyệt đối_tháng), và các (tháng_tuyệt đối) là liên tiếp. Hãy viết một số bài kiểm tra.
Bài kiểm tra của chúng tôi sẽ là một select
truy vấn SQL , với cấu trúc sau: tên bài kiểm tra và câu lệnh trường hợp được phân loại cùng nhau. Tên kiểm tra chỉ là một chuỗi tùy ý. Câu lệnh trường hợp chỉ là case when
các câu lệnh kiểm tra then 'passed' else 'failed' end
.
Các câu lệnh kiểm tra sẽ chỉ là các lựa chọn SQL (truy vấn con) phải đúng để kiểm tra vượt qua.
Đây là thử nghiệm đầu tiên của chúng tôi:
--a select statement that catenates the test name and the case statement
select concat(
-- the test name
'For every (year, month) there is one and only one (absolute_month): ',
-- the case statement
case when
-- one or more subqueries
-- in this case, an expected value and an actual value
-- that must be equal for the test to pass
( select count(distinct year, month) from month_value)
--expected value,
= ( select count(distinct absolute_month) from cm_absolute_month)
-- actual value
-- the then and else branches of the case statement
then 'passed' else 'failed' end
-- close the concat function and terminate the query
);
-- test result.
Chạy truy vấn đó tạo ra kết quả sau: For every (year, month) there is one and only one (absolute_month): passed
Miễn là có đủ dữ liệu thử nghiệm trong month_value, thì thử nghiệm này sẽ hoạt động.
Chúng tôi cũng có thể thêm một bài kiểm tra để có đủ dữ liệu kiểm tra:
select concat( 'Sufficient and sufficiently varied month_value test data: ',
case when
( select count(distinct year, month) from month_value) > 10
and ( select count(distinct year) from month_value) > 3
and ... more tests
then 'passed' else 'failed' end );
Bây giờ hãy kiểm tra nó liên tiếp:
select concat( '(absolute_month)s are consecutive: ',
case when ( select count(*) from cm_absolute_month a join cm_absolute_month b
on ( (a.month + 1 = b.month and a.year = b.year)
or (a.month = 12 and b.month = 1 and a.year + 1 = b.year) )
where a.absolute_month + 1 <> b.absolute_month ) = 0
then 'passed' else 'failed' end );
Bây giờ chúng ta hãy đặt các bài kiểm tra của chúng ta, chỉ là các truy vấn, vào một tệp và chạy tập lệnh đó trên cơ sở dữ liệu. Thật vậy, nếu chúng tôi lưu trữ các định nghĩa chế độ xem của mình trong một tập lệnh (hoặc các tập lệnh, tôi khuyên bạn nên chạy một tệp cho mỗi chế độ xem liên quan) để chạy trên cơ sở dữ liệu, chúng tôi có thể thêm các thử nghiệm của mình cho mỗi chế độ xem vào cùng một tập lệnh, để hành động của (lại -) việc tạo chế độ xem của chúng tôi cũng chạy các bài kiểm tra của chế độ xem. Bằng cách đó, cả hai chúng tôi đều nhận được các bài kiểm tra hồi quy khi chúng tôi tạo lại chế độ xem và khi quá trình tạo chế độ xem chạy ngược lại quá trình sản xuất, chế độ xem cũng sẽ được kiểm tra trong quá trình sản xuất.