1-12 Thao tác lập trình SQL

1-12 Thao tác lập trình SQL

>Hướng đến xác lập phong cách lập trình SQL Trong SQL thì phong cách lập trình thông thường chưa được hoàn thành, kim chỉ thống nhất đối với toàn bộ SQL cũng chưa được xác lập. Tại chương này sẽ hướng đến cấu trúc phong các lập trình SQL nên có trong tương lai, đây chỉ là những đề án của tác giả với tư cách như một đề án để thử nghiệm.

Cùng viết một cách dễ hiểu - Không thể hi sinh sự dễ hiểu để lấy tính hiệu quả được

-Brian W. Kernighan& P.J.Plauger [プログラム書法 第2版]

Mở đầu

Trong thế giới lập trình không chỉ yêu cầu những kĩ thuật cao đa dạng mà còn chú ý đến khả năng đọc hiểu code, nhìn từ quan điểm tiếp cận với sự phát triển chương trình một cách trơn chu đã hình thành nên lĩnh vực nghiên cứu phong cách lập trình.

Ngôn ngữ lập trình từ những ngôn ngữ trình độ thấp là những ngôn ngữ máy móc, chỉ chú ý đến điểm làm sao cho máy móc đọc dễ hiểu chuyển đến ngôn ngữ lập trình bậc cao mà con người cũng có thể đọc dễ dàng thì ý thức "Ngôn ngữ lập trình nên là ngôn ngữ để con người có thể đọc và viết" được nâng cao, từ đó sinh ra nghiên cứu về phong cách lập trình từ quan điểm từ một loại tâm lý học nhận thức. Nói là tâm lý học nhận thức thì có vẻ khó nghe nhưng đối với thái độ như "Chỉ cần chạy được là được rồi" hay "Hiệu quả là tất cả" thì đây là câu chuyện thường thức nên suy nghĩ kĩ xem làm thế nào để có thể viết được code ít lỗi mà ai cũng có thể dễ dàng để đọc thì chúng ta phải làm thế nào. Chắc cũng có nhiều người đã nghe đến khẩu lệnh KISS đúng không? (KISS là lược của "Keep it sweet & simple", cũng có thuyết cho rằng đó là "Keep it simple, stupid").

Nếu đưa ra một ví dụ đơn giản thì đối với 2 tấm card như dưới đây thì để đếm số được viết trên đó thì bên nào sẽ dễ hiểu hơn?

Untitled.png

Cả hai hình đều truyền tải thông tin có 5 hình tròn. Nhưng đối với nhiều người thì chắc chắn hình bên phải sẽ dễ nhìn hơn. Lý do này rất đơn giản, chúng ta từ nhỏ đã thông qua những lá bài hay con xúc xắc nhớ rằng hình ảnh này biểu thị ý nghĩa 5. Khi nhìn vào hình bên phải thì chúng ta không nhận thức như một ngôn ngữ là số mà chúng ta sẽ nhận thức nó như một bậc của hình ảnh. Như thế, những công việc trọ giúp cho việc hình dung sẽ sinh ra những tài liệu thuyết trình, bảng báo giao thông mà chúng ta hay nhìn thấy ở trên đường.

Đối việc xác lập phong cách lập trình thì về cơ bản cũng đang điên đầu để có được những hiệu quả tương tự. Đặc biệt là càng đối với những dự án lớn thì càng nhiều những cơ hội để người khác đọc code của mình hay mình đọc code của người khác, từ điểm này thì những dòng code cũng mang chức năng như một phương tiện giao tiếp. Nói như vậy thì nghiên cứu phong cách lập trình cũng chính là tìm kiếm phương thức để giao tiếp trơn chu nhất trong quá trình phát triển hệ thống. (Vậy nên nếu chỉ 1 người lập trình thì khó có thể nhận ra sự cần thiết của phong cách).

Nghiên cứu trong lĩnh vực này mang lại một tri thức cùng cách nhìn quan trọng về thế giới lập trình. Trong ngôn ngữ lập trình thủ tục là trào lưu hiện tại thì những điều này đã được sinh ra trong những cuốn sách cổ điển của Brian W. Kernighan& P.J.Plauger như プログラム書法 và プログラム作法, hoặc nó đã thể hiện được vị trí quan trọng của mình trong lĩnh vực giao diện người dùng.

Mặt khác, thì tác giả cho rằng đối với cơ sở dữ liệu thì có hiện tượng chưa hình thành đến đoạn ý thức về phong cách lập trình. SQL là một trong những ngôn ngữ không phải là ngôn ngữ lập trình thủ tục nên không thể cứ như thế phát huy hình thức đã tích tụ trong ngôn ngữ lập trình thủ tục, vì vậy đối với những ngôn ngữ như SQL thì sự thật là vẫn chưa được ý thức nên suy nghĩ cẩn thận đến vậy.

Tuy nhiên những năm gần đây thì SQL đã có những xử lý tính năng cao độ nên vẫn đang được nhìn lại. Trong tương lai thì SQL chắc hẳn sẽ có nhiều xử lý như mong đợi và sẽ trở thành một thứ phức tạp. Như vậy thì code cũng sẽ trở nên phức tạp. Vì vậy chương này tác giả muốn đưa ra những đề án đặt nền móng hướng đến việc trong tương lai, những kĩ sư cần thiết phải suy nghĩ để xác lập một phong cách lập trình.

Thiết kế bảng

Tên và ý nghĩa

Con người về tổng thế là loài vật sống rất yếu về những thứ vô ý nghĩa. Chúng ta hàng ngày từ công việc đến cuộc đời đều luôn muốn tìm kiếm ý nghĩa có trên mọi thứ. Nếu có một cuộc sống mà xung quanh chỉ có những thứ vô ý nghĩa thì kể cả về mặt tinh thần cũng có ảnh hưởng xấu và năng lực sử dụng những thứ vô ý nghĩa (hoặc những thứ ngẫu nhiên) nói chung là thấp chính là đặc trưng của con người.

Lý do lớn nhất dẫn đến việc cơ sở dữ liệu quan hệ có được vị trí lớn trong thế giới hệ thống, đó là vì chúng đưa địa chỉ cho những thứ vô ý nghĩa. Sau khi đưa địa chỉ vào thì thứ còn sót lại chính là tên. Tên chính cũng là thứ mang ý nghĩa chỉ những thứ cụ thể như danh từ riêng, cũng mang ý nghĩa chỉ những tập hợp, khái niệm như danh từ chung. Những thứ không thể nhìn ngay được tên nhưng nếu nhìn từ điểm chỉ thị khái niệm hay tập hợp thì ta có danh từ chung. Ví dụ từ để chỉ tập hợp như tập hợp "Nam" "Nữ" trong danh mục Giới tính, hay chỉ khái niệm như khái niệm "Cảm" "Sâu răng" trong danh mục Bệnh thì đó là danh từ chung. Ngược lại thì địa chỉ không chỉ bất cứ một khái niệm hay vật gì cả.

Đã mất công tạo lập nên một thế giới với những cái tên có ý nghĩa thì không thể để những lỗi như có những kí hiệu vô ý nghĩa. Chúng ta cùng gắn cho dãy, bảng, index những cái tên cụ thể biểu hiện chính nó. Nhất định không được nhầm lẫn mà sử dụng những kí hiệu vô ý nghĩa như "A" "AA" "idx_123". Đặc biệt đối với index hay chế ước thì chúng ta cần thiết chú ý nếu không đặt những cái tên rõ ràng thì DBMS sẽ tự động phụ chú như một dãy ngẫu nhiên.

Tuy nhiên đối với những người để ý đến tên của bảng thì cũng có xu hướng đặt những mệnh danh khó chấp nhận cho inline view trong code. Tuy nhiên, SQL sử dụng đến inline view cũng là những SQL phức tạp nên nhất thiết phải đặt những cái tên dễ hiểu.

Trong trường hợp đặt tên, thì chỉ có 3 loại kí tự sau mới được cho phép.

  • Chữ cái Alphabet
  • Chữ số
  • Dấu gạch dưới (_)

Đây không phải là những kí hiệu mà tác giả tự qui định mà là những tập hợp kí hiệu được cho phép trong SQL thông thường. Tuỳ từng thực hiện mà ngoài ra có thể mở rộng sử dụng những kí hiệu đặc biệt như $, #, @ hay những kí tụ 2 byte như chữ Hán nhưng nói chung nên tránh sử dụng những kí tự đó. Nó có thể trở thành nguyên nhân gây bug. Mặt khác trong SQL thông thường yêu cầu kí tự đầu tiên của tên là chữ cái nên cái này nhất định phải tuân theo. Nếu dãy chữ được bao bởi dấu hai nháy như "Primary" thì có thể sử dụng như tên cũng chỉ là hành động mời gọi thêm những hỗn loạn không đánh có nên tốt hơn hết là không nên sử dụng.

Thuộc tính và dãy

Chắc hẳn đến bây giờ chúng ta đã nhìn thấy những thiết kế bảng mang nhiều ý nghĩa cho một dãy.

Ví dụ như đối với bảng có những giá trị như phiếu ghi lại những thay đổi trong một năm thì theo thời điểm thay đổi mà ý nghĩa của giá trị ghi lại trong 1 dãy sẽ thay đổi. Hoặc là bảng quản lý bằng một dãy nhiều code như code khách tham quan, code các tỉnh thành.

Những thiết kế như thế này dựa theo cách suy nghĩ 'Tuỳ theo vị trí mà gọi ra dữ liệu' và đây trở thành qui định trong cơ sở dữ liệu quan hệ. Đối với DB thì dãy là thuộc tính vậy nên ở một mức độ nào đó thì nó được xem như là một sự tồn tại vĩnh viễn.

Với những thiết kế thay đổi liên tục ý nghĩa của dãy tuỳ từng trường hợp và thời điểm như lúc thì là số tuổi, lúc thì là trọng lượng, lúc thì là ... đối với hành động coding cũng trở nên khó hơn, thì trước đó nên đặt những cái tên thích hợp cho dãy của mình để tránh trường hợp đó.

Ví dụ giả sử chúng ta là một trại nuôi gà và hàng ngày đi nhặt những quả trứng để bán. Để quản lý những quả trứng đó thì chúng ta tạo bảng quản lý trong đó có cột quality để quản lý chất lượng những quả trứng. Giả sử đối với những người bán trứng như chúng ta thì chất lượng quả trứng được thể hiện qua khối lượng quả trứng đó và chúng ta điền vào cột quality khối lượng của quả trứng thu được như 60gr, 70gr,... rồi dựa vào đó để định giá. Nhưng khi mang ra thị trường thì khách hàng lại yêu cầu chất lượng của quả trứng ở đây phải là kích thước của quả trứng như đường kính, như vậy chúng ta lại về điều chỉnh lại số liệu trong cột quality. Việc thay đổi số liệu của một dãy lúc thì là khối lượng, lúc thì là đường kính của quả trứng đối với việc code cũng như đối với DBMS là điều không tốt. Dãy hay chính là cột quality ở đây chính là tính chất của dãy, nên từ đầu chúng ta không nên đặt tên một dãy không mang tính biểu hiện tính chất như vậy mà nên đặt tên dãy ví dụ như weight hay size rồi thêm dữ liệu.

Kim chỉ có việc lập trình

Comment

Comment trong phong cách lập trình trở thành một đề tài nghị luận đặc biệt. Trong đó tồn tại những ý kiến trái chiều mạnh mẽ như đối ngược có phái cho rằng nhất đinh phải có comment những cũng có phái phản đối cho rằng comment cuối cùng cũng chỉ làm giảm sự đọc hiểu đối với code, chúng ta hãy cùng để tâm hướng đến viết nên những code không cần comment cũng có thể hiểu được.

Đối với tác giả thì không nói đến các ngôn ngữ khác, chỉ giới hạn trong SQL thì nên có comment. Có 2 lý do lớn để dẫn đến điều đó, đầu tiên SQL là ngôn ngữ kiểu truyền ngôn nên cùng để ghi một xử lý mà so với ngôn ngữ lập trình thủ tục có những cách ghi bằng logic rất ngắn gọn.

Lý do thứ hai đó chính là vì SQL hầu hết không thể debug một cách giai đoạn được. Trong lúc phân tích lại code thì ai cũng muốn có thể debug được càng nhiều càng tốt.

Về cách viết comment thì chúng ta có 2 con đường.

--Comment dòng 1
--Hãy chọn col_1 từ SomeTable
SELECT col_1
  FROM SomeTable;
/*
Coment nhiều dòng
Hãy chọn col_1 từ SomeTable
*/
SELECT col_1
  FROM SomeTable;

Về cách viết [--] thì tôi nghĩ rằng ai cũng biết nhưng cách viết [/**/] giống như trong ngôn ngữ C hay Java thì chắc không nhiều người biết. Cách viết này không chỉ có thể sử dụng trong việc viết comment mà cũng có thể sử dụng trong comment out code.

Mặt khác, trong code của SQL thì không được có dòng trống nhưng chúng ta có thể chèn comment vào giữa code như dưới đây.

SELECT col_1
  FROM SomeTable;
 WHERE col_1 = 'a'
   AND col_2 = 'b'
   -- Điều kiện dưới đây chỉ col_3 là một trong 'c' và 'd'
   AND col_3 IN ('c', 'd');

Tính năng này trong trường hợp điều kiện của câu lệnh WHERE nằm liên tiếp mà cứ để như thế sẽ rất khó đọc, trong trường hợp này có thể dùng comment để chia các block theo ý nghĩa của nó nên rất tiện lợi. Trong trường hợp chúng ta viết comment cùng dòng với code nguồn cũng không có vấn đề gì xảy ra.

SELECT col_1   --Hãy chọn col_1 từ SomeTable
  FROM SomeTable;

Mọi người cũng hãy để tâm cố gắng gắn comment một cách chi tiết nhất có thể.

Lùi đầu dòng

Trong những trường hợp code khó đọc thì chắc hẳn trong đó trường hợp nhiều nhất sẽ là những code không có lùi đầu dòng.(Tiếp theo là trường hợp code kéo dài mãi mà không phân chia từng module).

Đặc biệt đối với những người mới bắt đầu lập trình vẫn chưa lý giải được tầm quan trọng của việc lùi đầu dòng, bắt đầu viết tất cả bắt đầu từ đầu dòng. Trong trường hợp những chương trình nhỏ dùng để học thì không có lùi đầu dòng cũng không gây hỗn loạn nên cũng không sao. Tuy nhiên đối với những người đã chuyên nghiệp trong lập trình mà không ý thức đến việc lùi đầu dòng trong code thì là việc không thể cho qua được. Dưới đây sẽ nêu ra ví dụ tốt và không tốt về việc lùi đầu dòng.

--Vì dụ tốt
SELECT col_1,
       col_2,
       col_3,
       COUNT(*)
  FROM tbl_A
 WHERE col_1 = 'a'
   AND col_2 = (SELECT MAX(col_2)
                  FROM tbl_B
                 WHERE col_3 = 100)
 GROUP BY col_1,
         col_2,
         col_3;
--Ví dụ không tốt
SELECT col_1, col_2, col_3, COUNT(*)
FROM   tbl_A
WHERE  col_1 = 'a'
AND    col_2 = (
SELECT MAX(col_2)
FROM   tbl_B
WHERE  col_3 = 100
) GROUP BY col_1, col_2, col_3;

Cũng như đã nhìn thấy thì đối với subquery thì chúng ta sẽ thực hiện lùi đầu dòng. Cái này nhất định phải tuân thủ. Cũng như chúng ta hiểu từ 'Sub' (cấp dưới) được gắn ở đầu thì nó là một level dưới so với truy vấn thông thường.

Tiếp theo trong trường hợp GROUP BY hay SELECT chỉ định nhiều đối tượng khác nhau thì cái này cũng trở thành bậc dưới. Trong trường hợp để ý đến việc làm như vậy sẽ làm tăng số dòng trong code thì chúng ta có thể tóm tắt lại trong 1, 3 hay 5 dòng hoặc có thể tóm tắt lại key bằng một đơn vị có ý nghĩa nào đó.

Trong ví dụ không tốt thì trước GROUP BY không có dòng được cắt ra, đây cũng là một cách viết không tốt. Trong SQL thì SELECT hay FROM đều là những câu lệnh có những công việc rõ ràng nên nhất định phải cách dòng theo đơn vị này. Hoặc, nếu vào chi tiết hơn câu chuyện thì theo ý kiến tác giả thì so với

SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY

thì việc sắp xếp như sau sẽ dễ đọc hơn,

SELECT
  FROM
 WHERE
 GROUP BY
HAVING
 ORDER BY

Dấu cách

Sử dụng ngôn ngữ nào cũng vậy, trong code cũng cần thiết có những khoảng trống một cách thích hợp. Nếu gắn chặt quá thì về ý nghĩa đơn vị cũng không rõ ràng và về mặt đọc hiểu cũng gây khó khăn.

--Ví dụ tốt
SELECT col_1
  FROM tbl_A A, tbl_B B
 WHERE ( A.col_1 >= 100 OR A.col_2 IN ( 'a', 'b'))
   AND A.col_3 = B.col_3;
--Ví dụ không tốt
SELECT col_1
  FROM tbl_A A,tbl_B B
 WHERE (A.col_1>=100 OR A.col_2 IN('a','b'))
   AND A.col_3=B.col_3;

Chúng ta cũng có thể hiểu luôn khi nhìn vào ví dụ không tốt, vì không có cách giữa nên chúng ta nhìn [A.col_1>=100] hay [A.col_3=B.col_3] thành một thành tố nên trở nên cực kì khó đọc. Tất nhiên code này sẽ không trở thành error nhưng nếu chúng ta cẩn thận đưa vào những dấu cách thì code cũng trở nên rõ ràng hơn, và cũng sẽ trở nên dễ đọc hơn cho mắt con người. Đây chỉ là điều cần chú ý một chút thôi nhưng mọi người hãy chú ý trong thường ngày nhé.

Chữ in hoa và chữ thường

Trong câu văn tiếng Anh, những chỗ cần nhấn mạnh thì người ta có văn hoá biến nó thành chữ in hoa. Chính vì vậy, đối với lập trình cũng vậy, đối với những cụm quan trọng hay những cụm không quan trọng thì cũng tiếp nối tập quán đó.

Trong trường hợp SQL, sự phân biệt trong sử dụng chữ in hoa và chữ thường, câu lệnh hay hàm thì được dùng chữ in hoa còn tên bảng, tên dãy thì được dùng chữ thường.(Đối với chữ đầu tiên của thành tố thì cũng có xu hướng sử dụng chữ in hoa, ví dụ như PlayStation, McDonald). Với cách thì không cần dùng dấu cách cũng có thể hiểu được đâu là một từ nên cách viết như thế này rất hay được sử dụng trong thế giới máy tính. Tất nhiên, trong thế giới SQL thì thỉnh thoảng chúng ta gặp những người viết tất cả bằng chữ in hoa hay tất cả bằng chữ thường cũng có nhưng nói chung không cần quá để ý.

--Ví dụ dễ đọc
SELECT col_1, col_2, col_3,
       COUNT(*)
  FROM tbl_A
 WHERE col_1 = 'a'
   AND col_2 = (SELECT MAX(col_2)
                  FROM tbl_B
                 WHERE col_3 = 100 )
 GROUP BY col_1, col_2, col_3;
--Ví dụ khó đọc: tất cả đều dùng chữ in thường
select col_1, col_2, col_3,
       count(*)
  from tbl_A
 where col_1 = 'a'
   and col_2 = (select max(col_2)
                  from tbl_B
                 where col_3 = 100 )
 group by col_1, col_2, col_3;
--Ví dụ dễ đọc
SELECT COL_1, COL_2, COL_3,
       COUNT(*)
  FROM TBL_A
 WHERE COL_1 = 'A'
   AND COL_2 = (SELECT MAX(COL_2)
                  FROM TBL_B
                 WHERE COL_3 = 100 )
 GROUP BY COL_1, COL_2, COL_3;

Dấu phảy

Tác giả cũng rất phân vân không biết có nên cho chủ đề này vào hay không nhưng suy nghĩ hướng đến mục đích trở thành bàn đạp của chương này nên cuối cùng cũng quyết định nêu ra chủ đề này ở đây.

Trong SQL thì chúng ta sử dụng dấu phảy để phân biệt các thành tố như bảng hay dãy. Dấu phảy thì có nhiều người sẽ nghĩ nó sẽ nằm đằng sau thành tố. Đúng là khi chúng ta viết [col_1, col_2, col_3] thì chúng trở thành một thứ tự là sau col_1 sẽ là dấu phảy, rồi sau col_2 cũng là dấu phảy,... nhưng như vậy thì không thể giải thích được lý do tại sao sau col_3 lại không có dấu phảy. Nhưng không có ý nghĩa dấu phảy là thứ được đặt trước các thành tố. Nếu vậy thì lần này chúng ta sẽ không giải thích được tại sao trước col_1 lại không có dấu phảy. Đáp án chính xác là,

Dấu phảy là thứ đặt giữa thành tố và thành tố

Nói vậy thì đây là một điều đương nhiên nhưng nếu để ý một chút thì chúng ta sẽ có cách viết như sau.

SELECT   col_1
       , col_2
       , col_3
       , col_4
  FROM tbl_A

Cũng như cách sử dụng dấu phảy trong ví dụ trên thì những dấu phép tính, AND và OR thì cũng có cách viết tương tự. Về phong cách viết dấu phảy trước như thế này có 2 ưu điểm. Đầu tiên là ngay cả khi col_4 bị xoá đi thì SQL sẽ không trở thành có lỗi mà vẫn hoạt động bình thường. Với cách viết thông thường thì khi xoá col_4 đi thì nội dung của câu lệnh SELECT sẽ là [col_3,] và sẽ thành error. Trong trường hợp này thì chúng ta còn phải một lần nữa xoá cả dấu phảy đi nữa. Trong cách viết này thì ngay cả thành tố đầu dòng là col_1 bị xoá đi thì chương trình vẫn chạy bình thường mà không phát sinh lỗi. Hầu hết đối tượng để thêm vào, xoá đi thì phần nhiều sẽ là những thành tố ở đầu hay cuối.

Ưu điểm thứ 2 chính là đối với những editor có tính năng chọn mà khung chọn là hình chữ nhật thì chúng ta có thể dễ dàng chỉnh sửa. Nếu viết dấu phảy ra đằng sau thì chiều dài của dãy theo dấu phảy đó sẽ trở nên khác nhau.

Nhưng đối ngược với hai ưu điểm trên thì nó mang theo một khuyết điểm, đó chính là làm giảm khả năng đọc hiểu. Có thể đối với những người đầu tiên đọc câu SQL được viết theo phong cách này sẽ dừng lại một chút và tự hỏi cách viết gì đây. Đây chẳng phải đang phản đối lại hoàn toàn lại mới mục đích ban đầu của chương này là "Yêu cầu một phong cách có độ dễ đọc cao sao?"

Đúng như vậy, điểm này đã tấn công một đòn đau. Để chuyển phong cách viết code từ một phong cách đã quen thì quả thật đây cần một sự cố gắng mang tính tinh thần cao. Đây chính là lý do ban đầu tác giả đã phân vân không biết có nên đưa chủ đề này vào không. Tuy nhiên trong SQL thì để khoogn coi nhẹ những lợi ích của dấu phảy thì tác giả đã tiến hành giới thiệu ở đây không biết mọi người đọc thì thấy thế nào?

Trong thế giới cơ sở dữ liệu thì tác giả của việc viết dấu phảy sau chắc hẳn đó chính là Celko. "Dấu phảy được viết không phải đầu câu mà là cuối câu. Ngay cả những dấu như dấu hỏi, dấu chấm đều là những kí hiệu thị giác biểu thị kết thúc một điều gì đó chứ không phải để bắt đầu một điều gì đó. (Joe Celko's SQL Programming Style, p.31)"

Đúng là dấu chấm hay dấu hỏi là dấu cuối câu để chỉ một điều gì đó kết thúc nhưng dấu phảy là dấu để nối những thành tố với nhau, về ý nghĩa đó thì nó mang tính năng y hệt AND và OR. Chính vì vậy, nếu chúng ta viết ở đầu câu thì cũng không có gì kì lạ.

Không sử dụng dấu sao *

Nếu chỉ định toàn dãy bằng * thì toàn dãy trong bảng sẽ được chọn. Đây là một phương thức đơn giản và tiện lợi nhưng tốt hơn hết là cố gắng không nên sử dụng. Nếu sử dụng * thì có thể trong dãy lựa chọn về mặt logic sẽ bao gồm những dãy không cần thiết như vậy sẽ giảm sự dễ đọc của code cũng như khó để sửa chữa cấu trúc. Cấu trúc của kết quả sẽ giống như thứ tự của dãy ban đầu nên nếu thay đổi thứ tự của dãy ban đầu hay thêm, bớt dãy sẽ là nguyên nhân dẫn đến sự xáo trộn trong kết quả.

× SELECT * FROM SomeTable;
○ SELECT col_1, col_2, col_3,... FROM SomeTable;

Mặc dù cũng hơi phức tạp một chút nhưng cũng nên cố gắng chỉ đinh những dãy cần thiết trong SELECT.

Không sử dụng số dãy trong ORDER BY

Tại ORDER BY thì chúng ta có thể chỉ định số dãy thay cho tên dãy trên thực tế. Đây là một tính năng rất tốt trong trường hợp tạo SQL động nhưng sẽ làm giảm độ dễ đọc một cách trầm trọng. Hơn nữa, lệnh này trong SQL-92 đã nằm trong danh sách "Tính năng nên xoá trong tương lai". Cũng giống như dấu * như ở trên thì đây là cách viết phụ thuộc vào vị trí, thứ tự của dãy nên nếu có sự thay đổi trong dãy sẽ gây ra sự hỗn loạn trong kết quả.

× SELECT col_1, col2 FROM SomeTable ORDER BY 1, 2;
○ SELECT col_1, col2 FROM SomeTable ORDER BY col_1, col2;

Cách lập trình SQL

Cùng nói tiếng toàn dân

SQL trong ngôn ngữ lập trình nói chung thuộc vào ngôn ngữ có nhiều tiếng địa phương và nó thể hiện tính đặc sắc không xấu và cũng không tốt này của mình trong chương trình. Nếu hỏi SQL có được lấy từ những từ toàn dân không thì câu trả lời là có nhưng chũng ta không nhìn thấy sự cố gắng để nâng cao sự thống nhất trong nó. (Mới nhất đối với hiện nay là SQL-2003). Đây cũng có một phần phải chấp nhận về mặt lịch sử. SQL thông thường rất nghèo nàn, không đủ để ứng dụng nên từng chương trình DB mà có những mở rộng riêng để bù đắp những thiếu sót đó.

Tuy nhiên, những năm gần đây thì hoạt động hoàn thiện SQL cũng được xúc tiến và hướng đến nâng cao tính thực dụng. Nhưng nếu chúng ta không để ý gì mà sử dụng những từ ngữ địa phương như của PostgreSQL sang Oracle hay SQLServer sang MySQL thì có thể chương trình sẽ không hoạt động, tính di chuyển giữa các DBMS rất thấp nên để lập trình trong môi trường DBMS không quen thì cần một sự khổ luyện không nhỏ. Cũng như trong cuộc sống thường ngày thì chúng ta nên có thói quen sử dụng tiếng toàn dân với những điều chú ý dưới đây.

  1. Không sử dụng dấu phép tính, hàm số là Implementation-dependent

Những hàm số Implementation-dependent đặc biệt xung quanh những hàm số biến đổi hay thao tác dãy chữ. Có nghĩa rằng không nên sử dụng những hàm số DECODE (Oracle), IF (MySQL), NVL (Oracle), STUFF (SQLServer),... Hãy cùng sử dụng những hàm thông dụng như hàm CASE hay COALESCE hay NULLIFF. Mặt khác, đối với những hàm số không những SQL mà còn có thể sử dụng trong những chương trình khác như SIGN, ABS, REPLACE thì cũng có thể dùng mà không gặp vấn đề trở ngại gì.

Điều đáng lo lắng ở đây là những tính năng mặc dù nó là SQL thông thường nhưng tuỳ theo tình trạng thực hiện chương trình mà kết quả khác nhau. Ví dụ như những thành tố nằm trong nhóm này là EXTRACT là hàm số chỉ ngày, hàm số POSITION hay dấu kết nối dãy chữ như [||]. Mặc dù đây là những tính năng được sử dụng với tần số cao nhưng bằng việc sử dụng nó thì tính hoán đổi là rất thấp. (Những vấn đề này chắc hẳn sẽ được giải quyết trong tương lai qua những hỗ trợ thực hiện chương trình)

  1. Sử dụng cấu trúc câu thông thường trong kết hợp Điều kiện kết hợp không phân biệt với điều kiện tìm kiếm thông thường thì đã viết cùng câu lệnh WHERE như sau.
SELECT *
  FROM Foo F, Bar B
 WHERE F.state = B.state
   AND F.city = 'Tokyo'

Trong SQL thông thường có những keyword biểu thị kiểu kết hợp như JOIN hay CROSS và giữa những điều kiện kết hợp thì có ON để phân cách.

--Kết hợp nội bộ và điều kiện kết hợp là F.state = B.state
SELECT *
  FROM Foo F INNER JOIN Bar B
    ON F.state = B.state
 WHERE F.city = 'Tokyo';

Như thế này thì chúng ta có thể dễ dàng đọc khi có sự phân cách giữa loại kết hợp và điều kiện kết hợp. Ngoài ra chúng ta cùng viết sử dụng LEFT OUTER JOIN, RIGHT OUTER JOIN và FULL OUTER JOIN. Cùng tránh những cách viết mang tính di chuyển thấp như dấu (+) (Oracle) hay (*=) trong SQLServer. Từ lược OUTER cũng được chấp nhận trong SQL thông thường. nhưng chúng ta cần phân biệt rõ ràng kết hợp nội bộ hay kết hợp ngoài nên cũng không nên lược đi mà cần viết đầy đủ thì tốt hơn.

Phía trái và phía phải

Trong kết hợp ngoài thì ta có 3 loại và kết hợp trái, phải và toàn bộ. Trong đó thì sức mạnh biểu hiện của kết hợp trái và phải là giống nhau nên về logic thì dùng cái nào cũng được.

Tuy nhiên, đối với tôi LEFT OUTER JOIN có một ưu điểm về mặt phong cách. Đó chính là phía cột của kết quả tất nhiên sẽ đi về phía bên trái nên bằng việc master phía bên trái của bảng thì SQL và hình dạng của hình dung kết quả sẽ đồng nhất. Việc này có tác dụng làm dễ hình dung hơn kết quả khi nhìn qua SQL. Trên thực tế thì lý do chúng ta nhìn thấy LEFT OUTER JOIN nhiều hơn một cách áp đảo trong những tài liệu khác nữa không phải vì lý do này hay sao?

Nhưng tại đây thì chúng ta lại có câu hỏi, tại sao những cột đề mục lại ở phía bên trái thì đây chắc hẳn là vì lý do mắt con người thường chạy từ phía bên trái. (Mọi người hãy nhớ xem trước máy bán hàng tự động thì mắt mình sẽ chạy từ bên nào sang nhé)

Viết câu lệnh FROM

Mọi người khi viết SQL thì hay viết từ câu lệnh nào? Nếu hỏi câu hỏi này thì chắc hẳn có nhiều người sẽ trả lời đó là từ câu lệnh SELECT. Tất nhiên, bắt đầu viết từ SELECT cũng không có vấn đề gì. Nếu có SQL nhỏ tầm 10 dòng thì bắt đầu viết từ cái gì cũng không quan trọng đến vậy. Tuy nhiên với cách viết này thì đối với SQL càng lớn càng phức tạp thì sẽ trở thành phương pháp khó hiểu và tốn thời gian, đây là cách nghĩ của tác giả dựa theo kinh nghiệm của ông.

Lý do là bộ phận trong câu lệnh SELECT trong SQL được thực hiện cuối cùng nhưng trong khi viết thì nó không được ý thức một cách mạnh mẽ. Thứ tự thực hiện trong SQL là,

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT (-> ORDER BY)

ORDER BY chính xác không phải là một bộ phận của SQL nên để ngoài dãy thực hiện này cũng không sao. Như vậy thì SELECT chính là bộ phận cuối cùng. Đó chính là lý do vì sao biệt danh của dãy đặt trong SELECT không được dùng trong GROUP BY, những vẫn có những DB hơi khác một chút mà vẫn cho phép điều này.

Công việc mà SELECT làm không có gì to lớn ngoài dùng để hiển thị ra mắt bề ngoài và tính toán ra những dãy tính toán. Nếu nói trong món ăn thì đó là bộ phận hoàn thiện gia vị trong món ăn. Vì hay thường được đặt vị trí ở đầu code nên chúng tạo nên sự bắt mắt cho ta nhưng suy nghĩ về mặt logic thì không quan tâm cũng không sao. HAVING, WHERE, GROUP BY có trách nhiệm lớn hơn nhiều.

Vì vậy trong những trường hợp phải viết những SQL phức tạp thì so với việc đột nhiên mở đầu bằng câu lệnh SELECT thì chúng ta bắt đầu bằng FROM sẽ thuận theo logic hơn. Trong trường hợp không biết nên viết gì trong câu lệnh SELECT thì viết bắt đầu từ FROM thì chắc chắn 100% chúng ta sẽ hiểu ra. (Không hiểu cái đó có nghĩa là chưa quyết định cấu trúc của bảng đang sử dụng nên trước khi suy nghĩ SQL thì chúng ta nên cố định thiết kế của bảng).

Nếu gọi phương pháp viết từ câu lệnh SELECT là con đường topdown thì nếu làm không làm như vậy sẽ là con đường bottomup. Nếu soi theo ngôn ngữ C thì việc đột nhiên viết từ hàm số main là topdown thì việc bắt đầu tạo từ những module bộ phận nhỏ rồi cuối cùng sắp xếp, kết hợp chúng lại với nhau chính là bottom-up. So sánh module của ngôn ngữ lập trình thủ tục với clause của SQL quả thực là một điều vô lý nhưng chúng ta chỉ cần hiểu đó là sự tương tự thôi là được.

Tóm tắt

Trong chương trước thì chúng ta đã theo đuổi sự hiệu quả trong SQL hi sinh sự dễ đoc của nó nhưng trong chương này khi những lời viết ở chương trước còn chưa khô mực thì đã nói rằng không thể theo đuổi sự hiệu quả trong SQL mà hi sinh đi tính dễ đọc, chính là đã nêu ra những ý kiến trái ngược hoàn toàn. Tính dễ đọc và tính hiệu quả là những tính chất không thể so sánh cái nào quan trọng hơn cái nào được, tất nhiên có những trường hợp mà ta có được cả 2 tính này là tốt nhất nhưng hai tính chất này thường đối đầu nhau rất nhiều.

Suy nghĩ của tác giả nếu hỏi về việc nghiêng về bên nào hơn thì ông nghiêng về những gì viết ở chương này hơn. Đó là vì vấn đề perfomance có thể được giải quyết bằng những kĩ thuật tiên tiến khi năng lực của máy hay tính năng của cơ sở dữ liệu ngày càng được nâng cao, nhưng đối với code khó đọc thì không gì có thể giải quyết được. Việc đảm bảo sự dễ đọc cho code chính là nhiệm cụ của những người lập trình. Thế nên để tác giả lựa chọn một trong hai tính dễ đọc hay tính hiệu quả thì ông nói sẽ không phân vân gì mà lực chọn tính dễ đọc của code.

Về lĩnh vực perfomance tunning thì ông có sở thích rất sâu về lĩnh vực đó, có thể mọi người cũng có thể hiểu sự phấn khích khi mất những 1 tiếng để sửa một truy vấn có thể chạy nhanh hơn 1 phút. Tuy nhiên như vậy thì theo như tác giả thì ông nghĩ lập trình trên cả với ý nghĩa là một công cụ để giao tiếp thì nghĩa vụ đầu tiên của những người lập trình, nhà phát triển chương trình đó chính là để tâm đến một cách biểu hiện cẩn thân và dễ hiểu.

Đối với những bạn muốn suy nghĩ sâu hơn về cách lập trình SQL thì có thể tham khảo những tài liệu dưới đây.

  1. Joe Celko "Joe Celko's SQL Programming Style" (Morgan Kaufmann Pub, 2005)

Đây là quyển sách viết về phong cách cũng như những kiến thức xung quanh cần có để thiết kế cũng như lập trình chứ không phải là cuốn sách viết về những kĩ thuật trực tiếp trong SQL. Đây là cuốn sách bắt đầu từ qui tắc đặt tên cho dãy và bảng rồi những ví dụ thiết kế bảng không được sử dụng, những phong cách lập trình không được có, cách sử dụng view, những gợi ý về ý tưởng mang tính luận tập hợp,... Đặc biệt là chương thứ 6 "Phương chỉ lập trình" và chương 10 "Suy nghĩ bằng SQL" thì mong muốn tất cả các kĩ sư DB đọc. Việc quyển sách này không có bản dịch chính là một sự đáng tiếc.

  1. Brian W.Kernighan & P.J.Plauger "プログラム書法 第2版”

Đây là cuốn sách cổ điển về phong cách lập trình. Không liên quan đến việc nó sử dụng những ví dụ rất cổ của ngôn ngữ lập trình thủ tục, hầu hết nội dung của cuốn sách này vẫn được sử dụng rộng rãi hiện nay. Quyến sách này chính là bằng chứng của những bản chất của lập trình được viết trong cuốn sách này.