Chuẩn bị cho kỳ thi 733 về Phát triển ứng dụng DB2 9, Phần 2: Thao tác dữ liệu DB2

Tìm hiểu các khái niệm cơ bản

Tìm hiểu về các khái niệm cơ bản của việc thao tác dữ liệu trong cơ sở dữ liệu DB2®. Đây là Phần 2 trong một loạt bài gồm chín hướng dẫn mà bạn có thể sử dụng để trợ giúp chuẩn bị cho kỳ thi lấy chứng chỉ Phát triển ứng dụng DB2 9 (kỳ thi 733).

Sunil Sabat, Giám đốc liên minh kỹ thuật, IBM

Sunil Sabat là giám đốc liên minh kỹ thuật tại IBM trong Tập đoàn phần mềm quản lý thông tin. Ông đã giành được bằng thạc sĩ khoa học (M.S.) về kỹ thuật máy tính và bằng MBA. Ông là một Chuyên gia CNTT được cấp chứng chỉ IBM. Ông cũng là chuyên gia về CompTIA và được cấp chứng chỉ Microsoft. Sau khi đã làm việc trên tất cả các cơ sở dữ liệu lớn hơn 10 năm qua, Sunil có một niềm đam mê với công nghệ cơ sở dữ liệu và việc sử dụng tối ưu hóa nó để giải quyết các bài toán kinh doanh và con người. Gần đây, ông đã làm việc với các ISV (các nhà cung cấp phần mềm độc lập), mang lại cho họ công nghệ XML khi sử dụng DB2 9



25 09 2009

Trước khi bạn bắt đầu

Hướng dẫn này gồm những gì?

Hướng dẫn này trình bày các khái niệm cơ bản về thao tác dữ liệu trong các cơ sở dữ liệu DB2, bao gồm các chủ đề sau:

  • Thay đổi dữ liệu (chèn, cập nhật, xóa).
  • Truy vấn một cơ sở dữ liệu xuyên nhiều bảng hoặc nhiều khung nhìn.
  • Sử dụng các bảng truy vấn được vật chất hóa (các MQT - materialized query tables).
  • Sử dụng các hàm SQL DB2 và các thủ tục được lưu sẵn.
  • Sử dụng các biểu thức bảng chung.
  • Xác định khi nào sử dụng các con trỏ (cursor) trong một chương trình SQL.
  • Nhận biết các kiểu con trỏ (chỉ đọc, có thể cập nhật được, có thể cuộn được).
  • Nhận biết các phạm vi của các con trỏ.
  • Thao tác các con trỏ.
  • Khả năng thao tác các đối tượng lớn (LOBs) (như CLOB [Character Large Objects - các đối tượng lớn ký tự] và BLOB [Binary Large Object - các đối tượng lớn nhị phân]).
  • Quản lý một đơn vị công việc (ví dụ, một giao dịch)

Đây là hướng dẫn thứ hai trong một loạt bài viết gồm bảy hướng dẫn mà bạn có thể sử dụng để trợ giúp chuẩn bị cho kỳ thi lấy chứng chỉ Phát triển ứng dụng của họ DB2 9.1 của IBM (kỳ thi 733). Các tài liệu trong hướng dẫn này chủ yếu trình bày các mục tiêu trong Phần 2 của bài thi, mang tên "Thao tác dữ liệu".

Bạn không cần một bản sao của DB2 9 để hoàn thành hướng dẫn này. Tuy nhiên, nếu bạn muốn, bạn có thể tải về miễn phí bản sao của DB2 Express-C 9 từ trang các phần tải về DB2 Express-C (DB2 Express-C downloads page).

Ai cần tìm hiểu hướng dẫn này?

Để tham dự kỳ thi Phát triển ứng dụng họ DB2 9.1, bạn đã phải vượt qua được kỳ thi căn bản về họ DB2 9.1 (kỳ thi 730). Bạn có thể sử dụng "Loạt bài hướng dẫn căn bản về họ DB2" (DB2 Family Fundamentals tutorial series) (xem phần Tài nguyên) để chuẩn bị cho kỳ thi đó. Đây là một loạt hướng dẫn rất phổ biến đã giúp cho nhiều người hiểu về các khái niệm căn bản về họ các sản phẩm DB2.

Hướng dẫn này là một trong những công cụ có thể trợ giúp bạn chuẩn bị cho Kỳ thi 733. Bạn cũng nên xem lại phần Tài nguyên ở phần cuối của hướng dẫn này để biết thêm nhiều thông tin hơn.

Phát triển ứng dụng liên quan đến việc lấy ra và thao tác dữ liệu. Trong DB2, các quy trình ấy bao gồm một số các phương pháp. Mặc dù các phương pháp này có thể được lập trình theo các ngôn ngữ khác nhau, các khái niệm vẫn như vậy bất kể ngôn ngữ triển khai thực hiện là gì. Hướng dẫn này là bước đầu tiên mà bạn nên tìm hiểu trước khi bắt đầu lập trình ứng dụng với DB2


Thay đổi và truy cập dữ liệu

Thay đổi dữ liệu

Thay đổi dữ liệu là một quá trình then chốt cần hiểu khi thiết kế một ứng dụng cơ sở dữ liệu. Nó phụ thuộc vào một vài yếu tố:

  • Mô hình dữ liệu và siêu dữ liệu (Dữ liệu danh mục, các kiểu, các giới hạn là gì và kiểm tra xem bạn có phải đối phó với chúng không?).
  • Các yêu cầu nghiệp vụ (Bạn cần tìm ra và sửa đổi dữ liệu trong cơ sở dữ liệu như thế nào?).
  • Quyền truy cập và đảm bảo an ninh tại mức người dùng, mức bảng và mức cột (Có cho phép một sự thay đổi đặc biệt không?).
  • Các giao diện để truy cập dữ liệu (Bạn giao tiếp với dữ liệu thay đổi như thế nào?).

Bạn nên sử dụng các khả năng DB2 nào trong việc thiết kế một ứng dụng? Người sử dụng không thể sửa đổi dữ liệu danh mục hệ thống. Các bảng danh mục và các khung nhìn lưu trữ siêu dữ liệu về định nghĩa vật lý và logic của dữ liệu. Lược đồ SYSIBM sở hữu các bảng, trong khi các khung nhìn với các bảng này thuộc sở hữu của lược đồ SYSCAT. Bạn có thể truy vấn danh mục để nhận được các thông tin có ích. Để thực hiện các sự lựa chọn thích hợp, bạn cần phải xem xét cả hai, thiết kế cơ sở dữ liệu và các môi trường đích cho các ứng dụng của bạn. Ví dụ, bạn có thể chọn để áp đặt một số các quy tắc nghiệp vụ trong việc thiết kế cơ sở dữ liệu của bạn thay cho việc đưa vào trong logic ứng dụng của bạn.

Các khả năng mà bạn sử dụng và phạm vi mà bạn sử dụng chúng có thể biến đổi rất nhiều. Các khả năng mà bạn cần phải xem xét bao gồm:

  • Truy cập dữ liệu bằng cách sử dụng:
    • SQL nhúng, bao gồm cả SQL nhúng cho Java (SQLJ).
    • DB2 CLI (DB2 Call Level Interface - Giao diện mức lời gọi của DB2), ODBC (Open Database Connectivity – Kết nối cơ sở dữ liệu mở) và JDBC.
    • Các đặc tả kỹ thuật của Microsoft.
    • DBI Perl.
    • Các sản phẩm truy vấn.
  • Kiểm soát các giá trị dữ liệu bằng cách sử dụng:
    • Các kiểu dữ liệu (làm sẵn hoặc do người dùng định nghĩa).
    • Các ràng buộc kiểm tra bảng.
    • Các ràng buộc toàn vẹn tham chiếu.
    • Các khung nhìn có sử dụng CHECK OPTION (tùy chọn kiểm tra).
    • Logic ứng dụng và các kiểu biến.
  • Kiểm soát mối quan hệ giữa các giá trị dữ liệu bằng cách sử dụng:
    • Các ràng buộc toàn vẹn tham chiếu.
    • Các bộ bẫy sự kiện (Trigger).
    • Logic ứng dụng.
  • Thi hành các chương trình tại máy chủ bằng cách sử dụng:
    • Các thủ tục được lưu sẵn.
    • Các hàm do người sử dụng định nghĩa
    • Các bộ bẫy sự kiện (Trigger).

Lợi thế chủ yếu trong việc chuyển giao logic tập trung vào dữ liệu từ ứng dụng sang cơ sở dữ liệu là ứng dụng của bạn trở nên độc lập hơn về dữ liệu. Logic xung quanh dữ liệu của bạn được tập trung vào một nơi, đó là cơ sở dữ liệu. Điều này có nghĩa là bạn có thể thay đổi dữ liệu hoặc logic dữ liệu một lần và có ảnh hưởng ngay lập tức đến tất cả các ứng dụng phụ thuộc vào dữ liệu đó.

Lợi thế cuối cùng này rất mạnh, nhưng bạn cũng phải xem xét đến việc bất kỳ logic dữ liệu nào đặt vào cơ sở dữ liệu cũng có ảnh hưởng đến tất cả những người sử dụng dữ liệu như nhau. Bạn phải xem xét xem các quy tắc và các ràng buộc mà bạn muốn áp đặt đối với dữ liệu có áp dụng cho tất cả những người sử dụng dữ liệu hay chỉ những người dùng của một ứng dụng riêng lẻ nào đó hay không.

Các yêu cầu ứng dụng của bạn cũng có thể giúp bạn quyết định xem có áp đặt các quy tắc tại cơ sở dữ liệu hay tại ứng dụng không. Ví dụ, bạn có thể cần xử lý các lỗi xác nhận hợp lệ về việc nhập dữ liệu vào theo trình tự cụ thể. Nói chung, bạn nên thực hiện kiểu xác nhận hợp lệ dữ liệu này trong mã ứng dụng. Bạn cũng nên xem xét môi trường tính toán tại nơi ứng dụng được sử dụng. Bạn cần phải xem xét sự khác biệt giữa thi hành logic trên các máy khách và thi hành logic trên máy chủ cơ sở dữ liệu (thường là mạnh hơn) khi sử dụng hoặc các thủ tục được lưu sẵn, các hàm do người dùng định nghĩa (UDFs) hoặc kết hợp cả hai. Trong một số trường hợp, cách tiếp cận đúng đắn là bao gồm cả sự thi hành logic trong ứng dụng (có lẽ tùy theo các yêu cầu ứng dụng cụ thể) lẫn thi hành logic trong cơ sở dữ liệu (có lẽ tùy thuộc vào những cách sử dụng tương tác khác bên ngoài ứng dụng).

Truy cập dữ liệu

Trong một cơ sở dữ liệu quan hệ, bạn cần phải sử dụng SQL để truy cập dữ liệu mong muốn của bạn. Tuy nhiên, bạn có một sự lựa chọn cách tích hợp SQL đó vào ứng dụng của bạn như thế nào. Bạn có thể chọn trong số các giao diện và các ngôn ngữ được hỗ trợ sau đây:

  • SQL nhúng
  • C/C++
  • COBOL
  • FORTRAN
  • Ngôn ngữ Java® (thông qua SQLJ hoặc JDBC)
  • REXX
  • DB2 CLI và ODBC
  • Các đặc tả kỹ thuật của Microsoft, bao gồm cả ADO.NET và OLE DB
  • Các ngôn ngữ Visual Basic, Visual C++ và .NET
  • Perl DBI
  • Perl
  • PHP
  • Các sản phẩm truy vấn như Lotus Approach (Cách tiếp cận Lotus), IBM Query Management Facility (Tiện ích quản lý truy vấn của IBM), Microsoft Access hoặc Microsoft Excel

Chương trình của bạn phải thiết lập một kết nối tới máy chủ cơ sở dữ liệu đích trước khi nó có thể chạy bất kỳ các câu lệnh SQL thực thi nào. Kết nối này nhận biết cả mã nhận dạng (ID) quyền hạn của người sử dụng đang chạy chương trình và cả tên của máy chủ cơ sở dữ liệu mà chương trình được chạy trên đó. Nói chung, tiến trình của ứng dụng của bạn chỉ có thể kết nối với một máy chủ cơ sở dữ liệu ở một thời điểm. Máy chủ này được gọi là máy chủ hiện tại. Tuy nhiên, ứng dụng của bạn có thể kết nối đến nhiều máy chủ cơ sở dữ liệu trong một môi trường cập nhật nhiều máy chủ. Trong trường hợp này, chỉ có một máy chủ có thể là máy chủ hiện tại.

Chương trình của bạn có thể thiết lập một kết nối tới một máy chủ cơ sở dữ liệu hoặc tường minh bằng cách sử dụng một câu lệnh kết nối, hoặc không tường minh, bằng cách kết nối với máy chủ cơ sở dữ liệu mặc định. Các ứng dụng Java cũng có thể thiết lập một kết nối thông qua một cá thể kết nối (Connection).

Truy vấn một cơ sở dữ liệu xuyên qua nhiều bảng

Bạn có thể truy vấn dữ liệu từ một hoặc nhiều bảng khi sử dụng một câu lệnh SELECT. Bạn cần có quyền hạn thích hợp để truy cập dữ liệu mà bạn truy vấn. Dữ liệu được trả về được biết đến như một tập kết quả.

Một câu lệnh SELECT chỉ rõ các tiêu chí cho dữ liệu mà tập kết quả phải tìm nạp dữ liệu đó. Nó không chỉ rõ cách thức trong đó DB2 trả về kết quả như thế nào. Trình tối ưu hóa DB2 đưa ra quyết định sau cùng bằng cách xây dựng một kế hoạch truy cập dựa vào các thống kê cơ sở dữ liệu hiện tại từ các bảng danh mục hệ thống và các kiểu kế hoạch mà nó đã được chỉ thị phải xem xét.

Bây giờ hãy xem một số câu lệnh SELECT mẫu. Câu lệnh dưới đây chọn tất cả các tên cửa hàng và các tên sản phẩm từ các bảng cửa hàng và bảng sản phẩm:

SELECT A.STORE_NAME, B.PRODUCT_NAME FROM STORE A, PRODUCT B

Store_name (tên cửa hàng) là một cột trong bảng có tên là cửa hàng (store). Product_name (tên sản phẩm) là một cột trong bảng có tên là sản phẩm (product).

Bây giờ xem một ví dụ khác. Trong bảng employee (nhân viên), bạn chọn số hiệu của phòng ban (WORKDEPT) và tiền lương tối đa của phòng ban (SALARY) đối với tất cả các phòng ban có tiền lương tối đa thấp hơn tiền lương trung bình trong tất cả các phòng ban khác:

SELECT WORKDEPT, MAX(SALARY)
FROM EMPLOYEE EMP_COR
GROUP BY WORKDEPT 
HAVING MAX(SALARY) < (SELECT AVG(SALARY)
FROM EMPLOYEE
WHERE NOT WORKDEPT = EMP_COR.WORKDEPT)

Làm việc với các bảng truy vấn được vật chất hóa (MQT)

Định nghĩa của một MQT là dựa trên kết quả của một truy vấn. Các MQT có thể cải thiện đáng kể hiệu năng của các truy vấn. Hướng dẫn này giới thiệu cho bạn về các MQT, các bảng tóm tắt và các bảng dựng tạm và chỉ ra cho bạn, qua các ví dụ làm việc, làm thế nào để xây dựng và chạy với các bảng truy vấn được vật chất hóa.

Một MQT là một bảng mà định nghĩa của nó dựa trên kết quả của một truy vấn. Dữ liệu được chứa trong một MQT là bắt nguồn từ một hoặc nhiều bảng được nêu trong định nghĩa MQT. Các bảng tóm tắt (hoặc các bảng tóm tắt tự động [ASTs]), đã quen thuộc với những người sử dụng DB2 IBM cho Linux, UNIX và Windows, được coi là một kiểu MQT chuyên biệt. Câu lệnh fullselect, một phần của định nghĩa một bảng tóm tắt, chứa một mệnh đề GROUP BY tóm tắt dữ liệu từ các bảng được tham chiếu trong fullselect.

Bạn có thể coi một MQT như là một loại khung nhìn được vật chất hóa. Cả các khung nhìn lẫn các MQT được định nghĩa trên cơ sở một truy vấn. Truy vấn trên đó một khung nhìn được định nghĩa sẽ chạy bất cứ khi nào khung nhìn được tham chiếu. Tuy nhiên, một MQT thực tế lưu trữ các kết quả truy vấn như là dữ liệu và bạn có thể làm việc với các dữ liệu có trong MQT thay cho dữ liệu có trong các bảng bên dưới. Các MQT có thể cải thiện đáng kể hiệu năng của các truy vấn, đặc biệt là các truy vấn phức tạp. Nếu trình tối ưu hóa xác định rằng một truy vấn hay một phần của một truy vấn có thể được giải quyết bằng cách sử dụng một MQT, truy vấn có thể được viết lại để tận dụng lợi ích của MQT. Vào lúc tạo bảng, một MQT có thể được định nghĩa là được duy trì bởi hệ thống hay là được duy trì bởi người sử dụng.

Dữ liệu trong kiểu bảng truy vấn được vật chất hóa này được duy trì bởi hệ thống. Khi bạn tạo ra kiểu MQT này, bạn có thể xác định xem dữ liệu của bảng là REFRESH IMMEDIATE hay REFRESH DEFERRED. Từ khóa REFRESH (làm mới) cho phép bạn chỉ rõ dữ liệu sẽ được duy trì như thế nào. DEFERRED có nghĩa là dữ liệu trong bảng có thể được làm mới vào bất kỳ lúc nào khi sử dụng câu lệnh REFRESH TABLE. Các MQT được duy trì bởi hệ thống, cả REFRESH DEFERRED lẫn REFRESH IMMEDIATE đều không cho phép các hoạt động chèn, cập nhật hoặc xóa được thực hiện đối với chúng. Tuy nhiên, các MQT được duy trì bởi hệ thống với chế độ REFRESH IMMEDIATE được cập nhật ngay theo các thay đổi đã thực hiện cho các bảng bên dưới như là một kết quả của các phép chèn, cập nhật hoặc xóa.

Phần sau chỉ ra một ví dụ tạo ra một MQT được duy trì bởi hệ thống với REFRESH IMMEDIATE. Bảng đó có tên là EMP, được dựa trên các bảng bên dưới là EMPLOYEE và DEPARTMENT trong cơ sở dữ liệu SAMPLE. Vì các MQT làm mới ngay lập tức (REFRESH IMMEDIATE) yêu cầu ít nhất một khoá duy nhất từ mỗi bảng được tham chiếu, xuất hiện trong danh sách lựa chọn của truy vấn, trước hết bạn định nghĩa một ràng buộc duy nhất trên cột EMPNO trong bảng EMPLOYEE và trên cột DEPTNO trong bảng DEPARTMENT. Mệnh đề DATA INITIALLY DEFERRED đơn giản có nghĩa là dữ liệu không được chèn vào trong bảng như là một phần của câu lệnh CREATE TABLE. Sau khi được tạo ra, MQT ở trạng thái đang chờ kiểm tra và không thể được truy vấn cho đến khi câu lệnh SET INTEGRITY được thi hành đối với nó. Mệnh đề IMMEDIATE CHECKED chỉ rõ rằng dữ liệu sẽ được kiểm tra so với truy vấn định nghĩa của MQT và được làm mới. Mệnh đề NOT INCREMENTAL chỉ rõ rằng việc kiểm tra tính toàn vẹn được thực hiện trên toàn bộ bảng.

CONNECT TO SAMPLE
...
ALTER TABLE EMPLOYEE ADD UNIQUE (EMPNO)
ALTER TABLE DEPARTMENT ADD UNIQUE (DEPTNO)

CREATE TABLE EMP AS (SELECT E.EMPNO, E.FIRSTNME, E.LASTNAME, E.PHONENO, D.DEPTNO,
 SUBSTR(D.DEPTNAME, 1, 12) AS DEPARTMENT, D.MGRNO FROM EMPLOYEE E, DEPARTMENT D
  WHERE E.WORKDEPT = D.DEPTNO)
   DATA INITIALLY DEFERRED REFRESH IMMEDIATE

SET INTEGRITY FOR EMP IMMEDIATE CHECKED NOT INCREMENTAL

Các hàm và các biểu thức

Các hàm SQL DB2 là gì?

Một hàm cơ sở dữ liệu là một mối quan hệ giữa một tập hợp các giá trị dữ liệu đầu vào và một tập hợp các giá trị kết quả. Có hai loại hàm: được cài đặt sẵndo người sử dụng định nghĩa.

  • Hàm SQL được cài đặt sẵn được cung cấp cùng với trình quản lý (manager) cơ sở dữ liệu. Chúng cung cấp một giá trị kết quả đơn lẻ và được nhận biết như là một phần của lược đồ SYSIBM. Ví dụ về hàm SQL được cài đặt sẵn bao gồm các hàm cột như AVG, các hàm toán tử như +, các hàm tạo khuôn mẫu như DECIMAL và các hàm khác, chẳng hạn như SUBSTR.
  • Các hàm do người sử dụng định nghĩa (UDFs) là các hàm được đăng ký vào một cơ sở dữ liệu trong SYSCAT.FUNCTIONS (khi sử dụng câu lệnh CREATE FUNCTION). Các UDF không bao giờ là một phần của lược đồ SYSIBM. Một tập hợp các hàm như vậy được cung cấp cùng với trình quản lý cơ sở dữ liệu trong một lược đồ có tên là SYSFUN.

DB2 cho phép những người dùng và các nhà phát triển ứng dụng mở rộng các chức năng của hệ thống cơ sở dữ liệu bằng cách áp dụng các định nghĩa hàm riêng của họ trong chính máy cơ sở dữ liệu. Các ứng dụng dựa trên các UDF thực hiện tốt hơn các ứng dụng có lấy ra các hàng từ cơ sở dữ liệu và áp dụng các hàm đó trên dữ liệu được lấy ra. Việc mở rộng các hàm cơ sở dữ liệu cũng cho phép cơ sở dữ liệu lợi dụng cùng các hàm trong máy mà một ứng dụng sử dụng, cung cấp thêm sự hiệp lực giữa ứng dụng và cơ sở dữ liệu. Việc sử dụng các hàm góp phần vào nâng cao năng suất cho các nhà phát triển ứng dụng vì nó có tính hướng đối tượng hơn. Ví dụ, bạn có thể lưu trữ giá cho một sản phẩm bằng đô la Mỹ, nhưng bạn có thể muốn có một ứng dụng cụ thể trích dẫn giá cả theo Bảng Anh. Bạn có thể sử dụng một hàm để thực hiện điều này:

SELECT UNIT_PRICE, CURRENCY('UK',UNIT_PRICE) FROM PRODUCT WHERE PRODUCT_ID = ?

Các chế độ FENCED và NOT-FENCED

Bạn có thể tạo các hàm trong C/C++, ngôn ngữ Java, hoặc OLE. Một hàm có thể chạy trong các chế độ FENCED (bảo vệ) hay NOT-FENCED (không được bảo vệ). Bạn nên phát triển một hàm trong chế độ FENCED trước khi chuyển sang chế độ NOT-FENCED. Một quá trình NOT-FENCED sẽ nhanh hơn, vì nó sử dụng bộ nhớ tác nhân (agent) DB2, trong khi một quá trình FENCED chạy bên trong chính quá trình db2udf riêng của nó. Một quá trình FENCED sử dụng bộ nhớ chia sẻ chung để giao tiếp với tác nhân gọi. Các hàm FENCED được lưu trữ trong sqllib/function còn các hàm không được bảo vệ được lưu trữ trong sqllib/unfenced.

Các hàm SQL được DB2 cung cấp

Hãy xem các ví dụ về một vài hàm SQL. Ví dụ đầu tiên lựa chọn tiêu đề và giá của tất cả các cuốn sách trong một bảng. Nếu giá của một tiêu đề sách là NULL, nó sẽ được hiển thị là 0.00.

SELECT TITLE, COALESCE(PRICE, 0.00) AS PRICE 
FROM TITLES;

Tiếp theo, bạn sẽ thấy một ví dụ có trả về một tên công ty và số lượng các ký tự có trong tên của công ty:

SELECT COMPANYNAME, LENGTH(COMPANYNAME)
FROM CUSTOMERS

Bây giờ hãy xem làm thế nào để bạn có thể trả về năm ký tự ở tận cùng bên phải của tên của mỗi tác giả:

SELECT RIGHT(AU_FNAME, 5) 
FROM AUTHORS

Ví dụ tiếp theo này, khi sử dụng bảng project, thiết lập biến chủ AVERAGE (decimal(5,2)) là mức trung bình của số nhân viên (PRSTAFF) của các dự án trong phòng ban (DEPTNO) tên là D11.

SELECT AVG(PRSTAFF)
INTO :AVERAGE
FROM PROJECT
WHERE DEPTNO = 'D11'

Có rất nhiều các hàm SQL khác được định nghĩa trong sổ tay tham khảo SQL DB2. Bạn luôn có thể viết hàm SQL riêng của bạn nếu DB2 không cung cấp một hàm như thế.

Sử dụng các biểu thức bảng chung

Một biểu thức bảng chung là một bảng tạm thời tại chỗ có thể được tham chiếu nhiều lần trong một câu lệnh SQL. Bảng tạm thời này chỉ tồn tại trong khoảng thời gian của câu lệnh SQL định nghĩa nó. Mỗi lần bảng chung được tham chiếu, các kết quả là như nhau. Một bảng tạm thời được định nghĩa trong một câu lệnh SQL sử dụng mệnh đề WITH. Đây là cú pháp:

WITH <COMMON NAME1> AS ( <SELECT EXPRESSION>), <COMMON NAME2> 
AS (<SELECT EXPRESSION), & SELECT <COLUMN> FROM <TABLE_NAME> <WHERE_CLAUSE>

<table_name> hoặc là một bảng trong cơ sở dữ liệu hoặc là một <Common name> được định nghĩa bởi câu lệnh SQL có mệnh đề WITH. Dưới đây là một ví dụ:

WITH PROD_QUANTITY  AS
(SELECT PRODUCT_ID,  SUM (QUANTITY) AS  QUANTITY
    FROM CUSTOMER_ORDER_ITEM
    GROUP BY PRODUCT_ID),

  TOTALS  AS
(SELECT  -1 AS PRODUCT_ID, SUM(QUANTITY) AS TOTAL)

SELECT PRODUCT_ID, QUANTITY  
 FROM PROD_QUANTITY
UNION
SELECT PRODUCT_ID, TOTALS
FROM TOTALS
ORDER BY 1 DESC

Trong ví dụ trên, prod_quantity được định nghĩa như là một biểu thức bảng chung. Nó được sử dụng cùng với một biểu thức bảng chung được gọi là totals. Câu lệnh SELECT cuối cùng chọn từ cả hai biểu thức bảng chung.

Bây giờ hãy xem một ví dụ khác:

WITH
  PAYLEVEL AS                                                 
    (SELECT EMPNO, EDLEVEL, YEAR(HIREDATE) AS HIREYEAR,           
        SALARY+BONUS+COMM AS TOTAL_PAY                                     
        FROM EMPLOYEE                                                         
        WHERE EDLEVEL > 16),                                                       

  PAYBYED (EDUC_LEVEL, YEAR_OF_HIRE, AVG_TOTAL_PAY) AS         
    (SELECT EDLEVEL, HIREYEAR, AVG(TOTAL_PAY)                  
         FROM PAYLEVEL                                            
         GROUP BY EDLEVEL, HIREYEAR)

  SELECT EMPNO, EDLEVEL, YEAR_OF_HIRE, TOTAL_PAY, DECIMAL(AVG_TOTAL_PAY,7,2)
    FROM PAYLEVEL, PAYBYED                                             
    WHERE EDLEVEL =  EDUC_LEVEL                                        
        AND HIREYEAR=  YEAR_OF_HIRE                              
        AND TOTAL_PAY < AVG_TOTAL_PAY

Biểu thức bảng chung này cũng bao gồm PAYLEVEL. Bảng kết quả này bao gồm một số hiệu nhân viên, năm mà người đó đã được thuê, tổng số tiền lương phải trả cho nhân viên đó và trình độ học vấn của anh ta hay chị ta. Chỉ có các hàng dành cho các nhân viên có một trình độ học vấn cao hơn 16 được đưa vào kết quả.

Danh sách cũng bao gồm một biểu thức bảng chung có tên là PAYBYED (viết tắt của "-tiền lương theo trình độ học vấn"). Nó sử dụng bảng PAYLEVEL để xác định trình độ học vấn, năm thuê và tiền lương trung bình trung bình của nhân viên được thuê trong cùng một năm và có trình độ học vấn như nhau. Các cột được bảng này trả về đã được gán các tên khác (ví dụ EDUC_LEVEL) với các tên cột được sử dụng trong danh sách chọn.

Cuối cùng, bạn đi tới truy vấn thật sự để tạo ra kết quả mong muốn. Hai bảng (PAYLEVEL, PAYBYED) được nối để xác định những cá nhân có một mức lương thấp hơn tiền lương trung bình phải trả cho những người được thuê trong cùng một năm. Lưu ý rằng PAYBYED được dựa trên PAYLEVEL, do đó PAYLEVEL được truy vấn hai lần một cách hiệu quả trong câu lệnh đầy đủ. Cả hai lần cùng một tập hợp các hàng như nhau được sử dụng trong việc tính toán truy vấn.

Sau khi bạn định nghĩa một biểu thức bảng chung, bạn có thể sử dụng nó trong một câu lệnh SQL như bạn làm đối với bất kỳ bảng nào khác. Bạn có thể sử dụng một biểu thức bảng chung nhiều lần như bạn muốn. Bạn thậm chí có thể tạo ra một một biểu thức bảng chung dựa vào một biểu thức bảng chung được tạo ra trước đó.


Khi nào sử dụng các con trỏ (cursors) trong một chương trình SQL

Con trỏ là gì? Khi nào bạn cần nó?

Một con trỏ (cursor) là một cơ cấu được sử dụng để thao tác các tập hợp câu trả lời nhiều hàng từ một truy vấn DB2. Có hai tình huống mà bạn cần có một con trỏ:

  • Khi một truy vấn trả về nhiều hơn một hàng.
    Một câu lệnh SELECT với một mệnh đề INTO là rất đơn giản để viết mã, nhưng chỉ cho phép trả về có một hàng. Không có mệnh đề nào trong một câu lệnh SELECT cho phép xử lý trực tiếp được nhiều hàng, do đó, phải sử dụng một con trỏ.
  • Khi bạn muốn cập nhật hoặc xóa một hoặc nhiều hàng, nhưng trước tiên cần phải kiểm tra các nội dung của chúng.
    Cách đơn giản nhất để cập nhật hoặc xóa các hàng là sử dụng một câu lệnh như sau:

    UPDATE staff SET salary = salary * 1.10 WHERE id = 100

    hoặc

    DELETE FROM staff WHERE id = 100

    Tuy nhiên, các câu lệnh này, được gọi là các cập nhật hoặc xóa tìm kiếm không cho phép chương trình kiểm tra các nội dung của các hàng trước khi cập nhật hoặc xóa. Để thay thế bạn có thể sử dụng một con trỏ liên hợp với một cập nhật hoặc xóa được định vị Cách làm này cũng được biết đến như là "Update Where Current Of - Cập nhật khi đang ở đấy" và "Delete Where Current Of – Xóa khi đang ở đấy" trong đó " Current Of - đang ở đấy" nói đến hàng mà con trỏ hiện đang trỏ vào.

Để sử dụng một con trỏ, bạn cần phải khai báo nó, mở nó, tìm nạp các hàng từ nó, mỗi hàng một lần, cập nhật hoặc xóa (tùy trường hợp) các hàng mà con trỏ đang trỏ vào và đóng con trỏ lại. Bạn sẽ thấy nhiều chi tiết hơn và các ví dụ trong phần này và các phần sau.

Hỗ trợ con trỏ thay đổi tùy theo giao diện DB2 như thế nào

Sự hỗ trợ và thuật ngữ con trỏ thay đổi giữa các giao diện lập trình DB2 khác nhau. Bây giờ hãy xem xét nhanh các sự khác biệt đó. Sau đó, trong phần thao tác các con trỏ, bạn sẽ xem một số ví dụ cho SQL nhúng.

Chính ngôn ngữ SQL cung cấp sự hỗ trợ cơ bản cho các con trỏ, thông qua các câu lệnh DECLARE CURSOR, OPEN, FETCHCLOSE.

Bạn có thể thực hiện các cập nhật và xoá định vị con trỏ thông qua cú pháp sau đây:

UPDATE [OR DELETE] ... WHERE CURRENT OF <CURSOR NAME>

Các giao diện khác nhau xây dựng hỗ trợ con trỏ của SQL bằng nhiều cách khác nhau. Các ngôn ngữ lập trình truyền thống, ví dụ như: C, C++ và COBOL, cung cấp sự hỗ trợ tường minh cho việc khai báo và sử dụng con trỏ trong SQL nhúng tĩnh và nhúng động . Các hàng chỉ có thể được xử lý từng hàng một, theo hướng thuận.

Ngôn ngữ thủ tục SQL hỗ trợ các con trỏ giống như ngôn ngữ C đã làm, nhưng với mệnh đề WITH RETURN được bổ sung thêm để hỗ trợ trả về một tập kết quả cho bên gọi thủ tục được lưu sẵn.

Trong CLI DB2, các con trỏ không được khai báo tường minh, nhưng CLI tự động tạo ra chúng khi các hàm SQLExecute() hoặc SQLExecDirect() được gọi. CLI cung cấp các khả năng bổ sung thêm, xây dựng dựa trên sự hỗ trợ của con trỏ, ví dụ như khả năng phục hồi lại, để nhận được một mảng các hàng cùng một lúc và để di chuyển theo hướng tiến nhiều hơn một hàng.

Trong JDBC, một con trỏ được tạo ra tự động khi một đối tượng ResultSet được tạo ra. Khả năng bổ sung thêm có sẵn cũng giống như khả năng của CLI.

Sự hỗ trợ con trỏ của SQLJ về cơ bản là một sự pha trộn những gì có trong JDBC và SQL, nhưng trong SQLJ cái tương đương với con trỏ được gọi là con lặp (iterator).

Các công cụ tương tác, chẳng hạn như Trình xử lý dòng lệnh và Trung tâm điều khiển DB2 (DB2 Command Line Processor (CLP) and Control Center), không cho phép bạn sử dụng trực tiếp các con trỏ. Tuy nhiên, bản thân các công cụ ấy thì có sử dụng các con trỏ. Khi bạn thi hành câu lệnh SELECT thông qua CLP hoặc một yêu cầu nội dung mẫu cho một bảng trong Trung tâm điều khiển, một trỏ được sử dụng để trả về các hàng.

Một ví dụ đơn giản: Cách sử dụng con trỏ trong SQL nhúng tĩnh

Trước khi thảo luận thêm về các con trỏ, hãy xem xét một ví dụ về một con trỏ rất đơn giản trong SQL nhúng tĩnh (một chương trình C).

EXEC SQL DECLARE C0 CURSOR FOR SELECT DEPTNUMB, DEPTNAME FROM ORG;

EXEC SQL OPEN C0;

EXEC SQL FETCH C0 INTO :DEPTNUMB, :DEPTNAME;
WHILE (SQLCA.SQLCODE != 100)  /* CONTINUE UNTIL THE END OF THE RESULT SET */
{
PRINTF("    %8D %-14S\N", DEPTNUMB, DEPTNAME);
EXEC SQL FETCH C0 INTO :DEPTNUMB, :DEPTNAME;
}

EXEC SQL CLOSE C0;

Mã lệnh này in số hiệu và tên của tất cả các phòng ban trong bảng org. Câu lệnh DECLARE CURSOR cung cấp truy vấn được sử dụng và câu lệnh OPEN chuẩn bị các tập hợp kết quả cho truy vấn. Một câu lệnh FETCH được sử dụng lặp lại nhiều lần để chuyển các giá trị của các cột của tập kết quả vào các biến chương trình, mỗi lần một hàng, cho đến khi đến hàng cuối cùng của tập kết quả (SQLCODE = +100), lúc ấy con trỏ được đóng lại.


Nhận biết các kiểu con trỏ

Các đặc điểm của con trỏ

Có ba đặc điểm chính của các con trỏ:

  • Kiểu con trỏ: Chỉ đọc, cập nhật được, hoặc mơ hồ.
  • (Các) hướng con trỏ: Chỉ hướng thuận, hoặc cuộn được.
  • Phạm vi con trỏ.

Các đặc điểm này sẽ được thảo luận trong một số phần tiếp theo.

Kiểu con trỏ

DB2 xử lý mỗi kiểu trong ba kiểu con trỏ hơi khác nhau một chút, các sự khác biệt chủ yếu trong lĩnh vực hiệu năng. Hãy xem xét từng kiểu.

Các con trỏ chỉ đọc

Khi DB2 biết rằng một con trỏ là chỉ đọc, một số lợi thế về hiệu năng nhất định có thể được áp dụng:

  • DB2 thường thực hiện việc chặn (blocking) bản ghi để lấy ra nhiều hàng từ máy chủ cùng một lúc và không cần phải lo lắng để lấy được các khóa cho phép các hàng có thể được cập nhật.
  • DB2 đôi khi có thể chọn một kế hoạch truy cập tốt hơn cho truy vấn.

Nếu bạn biết rằng một con trỏ sẽ không được sử dụng để cập nhật hoặc xóa các hàng, bạn nên chỉ rõ nó như là con trỏ chỉ đọc bằng cách thêm FOR READ ONLY (hoặc FOR FETCH ONLY) vào câu lệnh SELECT dành cho con trỏ. Một con trỏ cũng được (tự động) xếp vào loại chỉ đọc nếu câu lệnh SELECT của nó là một phép nối (join) nhiều bảng hoặc có chứa các mệnh đề như ORDER BY hoặc GROUP BY.

Các con trỏ cập nhật được

Một con trỏ là cập nhật được nếu mệnh đề FOR UPDATE được chỉ rõ trong câu lệnh SELECT của nó, có nghĩa là các hàng được cập nhật thông qua một câu lệnh Update Where Current Of. Chỉ có thể có một bảng (hoặc chỉ một khung nhìn) được tham chiếu trong câu lệnh SELECT đó. Do nó phải duy trì tính toàn vẹn dữ liệu, nên DB2 chỉ có thể thực hiện rất ít việc tối ưu hóa cho các con trỏ cập nhật được.

Thuật ngữ con trỏ xóa được được sử dụng trong Tài liệu tham khảo SQL như một cách để giúp định nghĩa các con trỏ cập nhật được. Hai thuật ngữ hầu như cùng một ý nghĩa. Xem mô tả về DECLARE CURSOR trong Tài liệu tham khảo SQL để biết thêm chi tiết.

Con trỏ mơ hồ

Như tên cho thấy, một con trỏ là mơ hồ khi DB2 không thể xác định từ định nghĩa con trỏ, nó là chỉ đọc hay cập nhật được. Nói cách khác, khi câu lệnh SELECT của con trỏ đã không chỉ rõ FOR READ ONLY và cũng không chỉ rõ FOR UPDATE, nó là mơ hồ. Đối với một con trỏ mơ hồ, DB2 sẽ chọn xem có thực hiện hay không việc ngăn chặn bản ghi để lựa chọn dựa trên giá trị của tùy chọn BLOCKING trên lệnh BIND dành cho ứng dụng không. Nếu việc ngăn chặn được thực hiện nhưng các việc cập nhật xảy ra, có một tác động tiêu cực đến hiệu năng, do đó, tốt nhất là cần tránh các con trỏ mơ hồ mỗi khi có thể.

Hướng con trỏ

Sự hỗ trợ con trỏ dành cho các ứng dụng SQL nhúng của DB2 cho phép chỉ có một hàng được xử lý tại một thời điểm và chỉ theo hướng thuận. Nói cách khác, mỗi câu lệnh FETCH trả về cho ứng dụng hàng tiếp theo của tập kết quả và không có cách nào khác để cho ứng dụng có được các hàng thông qua con trỏ.

CLI và nền tảng Java hỗ trợ các con trỏ cuộn được. Các con trỏ này có thể được định vị bằng cách đánh số hàng theo thứ tự tuyệt đối từ đầu trong tập kết quả (hoặc hướng thuận hoặc hướng ngược lại từ vị trí hiện tại) hoặc được di chuyển đi một số hàng nhất định khi so tương đối (thuận hoặc ngược) kể từ vị trí hiện tại. Để biết thêm thông tin về các con trỏ cuộn được, xem hướng dẫn thứ tư và thứ năm trong loạt bài này (trên ODBC/CLI và trên nền tảng Java tương ứng, xem phần Tài nguyên).

Phạm vi của con trỏ

Khi nói đến phạm vi, nó có nghĩa là khoảng thời gian mà trong đó con trỏ có sẵn để tìm nạp các hàng. Khoảng thời gian đó bắt đầu khi câu lệnh OPEN của con trỏ đã thực hiện thành công. Theo mặc định, phạm vi của con trỏ kết thúc khi con trỏ được đóng lại hoặc khi một lệnh cam kết được thực hiện. Như bạn sẽ thấy trong phần thảo luận tiếp theo, để lệnh cam kết chấm dứt phạm vi con trỏ có thể là một điều phiền toái, nhưng có một cách tránh điều này.

Các con trỏ WITH HOLD

Thông thường, các ứng dụng sẽ được viết để các câu lệnh COMMIT (cam kết) được thi hành khá thường xuyên. Lệnh cam kết này làm cho các khóa được giải phóng và chúng giảm thiểu các vấn đề tương tranh giữa các ứng dụng. Tuy nhiên, lệnh cam kết có thể gây ra vấn đề khi nó đến với các con trỏ. Đây là nơi cần đến mệnh đề WITH HOLD.

Như một ví dụ, hãy xem xét một ứng dụng trong đó một câu lệnh SQL đọc 10.000 hàng bằng cách sử dụng một con trỏ. Ứng dụng kiểm tra nội dung của mỗi hàng và cập nhật hàng đó để thiết lập giá trị của một cột trạng thái. Chờ cam kết cho đến khi tất cả các 10.000 hàng đã được xử lý có thể gây ra xung đột khóa, vì thế nó cam kết sau mỗi 20 hàng. Tuy nhiên, theo mặc định, lệnh cam kết đóng con trỏ, nên vị trí trong tập kết quả sẽ bị mất và ứng dụng sẽ phải làm một số việc xử lý đặc biệt để tiếp tục đúng từ vị trí nơi nó vừa rời bỏ.

Giải pháp cho vấn đề này là thay đổi định nghĩa con trỏ, đưa thêm vào mệnh đề WITH HOLD. Điều này làm cho lệnh cam kết để nguyên con trỏ ở trạng thái mở và tránh giải phóng các khóa cần thiết để duy trì vị trí của con trỏ. Nói cách khác, mệnh đề WITH HOLD kéo dài phạm vi của một trỏ vượt ra ngoài lệnh cam kết. Dưới đây là một ví dụ của một con trỏ WITH HOLD:

DECLARE C1 CURSOR WITH HOLD FOR SELECT * FROM STAFF

Mệnh đề WITH HOLD không có hiệu lực với những gì xảy ra với một con trỏ trong khi phục hồi. Con trỏ được đóng lại và tất cả các khóa có liên quan được giải phóng.


Thao tác các con trỏ

Tổng quan về xử lý con trỏ

Trong phần này, bạn sẽ xem xét tỷ mỉ hơn về các con trỏ được sử dụng như thế nào trong các ứng dụng SQL nhúng. Các bước cơ bản, một lần nữa, là khai báo, mở, tìm nạp, cập nhật/xóa (tùy trường hợp) và đóng.

Để giúp hiểu được khái niệm về một con trỏ, hãy giả sử rằng DB2 xây dựng một bảng kết quả để giữ tất cả các hàng được lấy ra bằng cách thi hành câu lệnh SELECT. Một con trỏ làm cho các hàng từ bảng kết quả trở thành sẵn sàng cho một ứng dụng xử lý bằng cách chỉ rõ hoặc trỏ vào hàng hiện tại của bảng này. Khi một con trỏ được sử dụng, một ứng dụng có thể lấy ra từng hàng từ bảng kết quả một cách tuần tự cho đến khi điều kiện hết dữ liệu (có nghĩa là, điều kiện NOT FOUND (không tìm thấy), SQLCODE +100 hoặc SQLSTATE 02000) thỏa mãn. Tập hợp các hàng có được như là một kết quả của việc thi hành câu lệnh SELECT có thể không có, có một, hay có nhiều hàng, tùy thuộc vào số lượng hàng thỏa mãn điều kiện tìm kiếm.

Khai báo một con trỏ trong SQL nhúng

Cú pháp của câu lệnh DECLARE CURSOR rất đơn giản. Dưới đây là một ví dụ cho SQL tĩnh:

DECLARE C1 CURSOR FOR SELECT * FROM STAFF

Việc sử dụng câu lệnh có thể gây một chút bối rối vì câu lệnh đó không được thi hành. Nói cách khác, câu lệnh được xử lý chỉ riêng trong giai đoạn chuẩn bị của ứng dụng nhúng và khi đi đến câu lệnh DECLARE trong thời gian thực hiện chương trình, không có gì xảy ra cả. Công việc bắt đầu thực hiện khi con trỏ đã được mở. Yêu cầu duy nhất đó là câu lệnh DECLARE CURSOR xuất hiện trước câu lệnh OPEN trong tệp tin nguồn. Nó thậm chí không cần phải nằm trong cùng một hàm C. Tên của mỗi con trỏ phải là duy nhất trong tệp tin nguồn ở đó nó được khai báo.

Nếu bạn đang sử dụng SQL động, câu lệnh DECLARE CURSOR có hơi khác một chút. Thay vì bao gồm cả cú pháp của câu lệnh SELECT bạn nên sử dụng một tên câu lệnh. Tên câu lệnh đó phải phù hợp với tên được sử dụng khi chuẩn bị câu lệnh SELECT có liên quan. Ví dụ:

EXEC SQL PREPARE STMT1 FROM :STRINGSTMT;
EXEC SQL DECLARE C3 CURSOR FOR STMT1;

Mở một con trỏ trong SQL nhúng

Việc mở một con trỏ chuẩn bị các hàng của tập kết quả truy vấn để cho chương trình sử dụng. Nó cũng định vị con trỏ trước hàng kết quả đầu tiên, mặc dù hàng đó không thể truy cập được bởi chương trình cho đến khi một lệnh tìm nạp được thi hành.

Thông thường, việc mở là ở nơi cần sử dụng một lượng thời gian lớn khi thi hành truy vấn, nhất là nếu có một mệnh đề ORDER BY hoặc GROUP BY trong câu lệnh chọn.

Cú pháp của một câu lệnh OPEN rất đơn giản. Để mở một trỏ có tên là "c0", bạn sẽ sử dụng lệnh sau:

OPEN C0

Tìm nạp một con trỏ trong SQL nhúng

Việc thi hành một lệnh tìm nạp dựa vào một con trỏ làm cho hàng tiếp theo của tập kết quả sẵn sàng cho chương trình xử lý, thông thường bằng cách đặt các giá trị của các cột của tập kết quả vào các biến chủ. Cột thứ n trong tập kết quả được đặt trong biến chủ thứ n trong tìm nạp.

Ví dụ, nếu một trỏ c0 được khai báo cho lệnh Select name, dept, id from staff, câu lệnh Fetch c0 into :hv1, :hv2, :hv3 sẽ đặt giá trị của cột name vào hv1, dept vào hv2id vào hv3.

Nếu bất kỳ cột của nào của tập kết quả có khả năng rỗng (nullable), một mã nhận dạng biến chủ thứ hai (chỉ báo null) sẽ được sử dụng và DB2 sẽ lưu trữ một giá trị âm trong biến đó để biểu diễn một giá trị null được trả về. Ví dụ, khi thay đổi ví dụ trước đây thành Fetch c0 into :hv1, :hv2 :hv2ind, :hv3 sẽ cho phép chương trình biết hàng của nhân viên nào có cột phòng ban là null.

Thông thường, một việc tìm nạp được đặt bên trong vòng lặp chương trình, được viết để tiếp tục cho đến khi trả về một SQLCODE +100 . Tại thời điểm này, tất cả các hàng trong tập kết quả đã nạp xong.

Cập nhật và xoá các hàng với một con trỏ

Như đã đề cập trước đó, một việc cập nhật hoặc xóa được định vị có thể được thực hiện trên hàng mà ở đó con trỏ được định vị. Một việc tìm nạp phải được thực hiện trước đó và không trả về SQLCODE +100 ((hay một lỗi). Mỗi hàng có trong tập kết quả có thể được xử lý theo cách này -- hoặc không một hàng nào trong chúng có thể được xử lý, hay bất kỳ số lượng hàng nào ở giữa. Dưới đây là một ví dụ:

EXEC SQL DECLARE CURSOR C0 FOR SELECT NAME, SALARY FROM STAFF FOR UPDATE OF DEPT;	
EXEC SQL FETCH C0 INTO :HVNAME, :HVSAL;
/* THERE MIGHT BE PROGRAM LOGIC HERE TO CHECK THE EMPLOYEE NAME AND SALARY */
/* AND ONLY EXECUTE THE UPDATE IF SOME CRITERIA APPLY                      */
EXEC SQL UPDATE STAFF SET DEPT = :NEWDEPT WHERE CURRENT OF C0;

Mã lệnh này lấy ra thông tin nhân viên từ bảng STAFF và cho phép cập nhật phòng ban của nhân viên. Câu lệnh DECLARE CURSOR cung cấp truy vấn, liệt kê các cột name và cột salary là các cột được trả về và cho biết rằng cột dept (phòng ban) có thể được cập nhật trong một số hàng. Câu lệnh FETCH đặt các giá trị nhân viên và tiền lương vào các biến chương trình. Câu lệnh UPDATE được sử dụng để thay đổi giá trị của cột dept trong hàng được tìm nạp trước đó thành giá trị trong biến chương trình newdept.

Mặc dù không được hiển thị ở đây, logic chương trình thường được sử dụng để tạo vòng lặp cho đến khi đi đến điểm cuối của tập kết quả và có thể đã được sử dụng để chỉ cập nhật một số hàng nhất định.

Đóng một con trỏ

Đóng một trỏ giải phóng bộ nhớ trong dành cho con trỏ và làm cho con trỏ không còn sẵn sàng để sử dụng thêm. Cú pháp rất đơn giản:

CLOSE C0

Theo mặc định, việc đóng một con trỏ không giải phóng các khóa mà nó đang giữ. Để thực hiện điều này, thêm vào mệnh đề WITH RELEASE:

CLOSE C0 WITH RELEASE

Điều này làm cho DB2 cố gắng để giải phóng tất cả các khóa đọc. Tuy nhiên, DB2 giữ tất cả các khóa trên các hàng được cập nhật và có thể cần phải giữ lại một số các khóa đọc cho các phép toán hoặc các hoạt động khác.

Con trỏ có thể được đóng tại bất kỳ lúc nào khi nó đang mở. Tức là, không cần phải tìm nạp toàn bộ tập kết quả trước khi đóng con trỏ. Sau khi một trỏ được đóng lại, nó có thể được mở lại và nó hoạt động cứ như là nó đã chưa hề được sử dụng trước đó.


Quản lý một đơn vị công việc

Một giao dịch là gì?

Thuật ngữ đơn vị công việc (unit of work-UOW), có cùng nghĩa với khái niệm một giao dịch. Nó được định nghĩa như là gồm không hay nhiều truy vấn SQL mà cần thi hành như chỉ một hoạt động không chia cắt được (atomic). Ví dụ, khi một khách hàng thực hiện một giao dịch mua hàng trực tuyến từ trang Web IBM, có ba bước phải được thực hiện:

  1. Cập nhật kiểm kê hàng hóa của gian hàng (mall) trên Web IBM.
  2. Khách hàng phải trả tiền cho các mục đã mua.
  3. Mỗi mục đã mua phải được vận chuyển đi.

Điều gì sẽ xảy ra nếu các bản ghi kiểm kê hàng hóa đã được cập nhật và khách hàng đã trả tiền, nhưng vận đơn đã không bao giờ được tạo ra? Không những bạn sẽ có một khách hàng tức giận vì không nhận được hàng hóa đã mua của mình, mà bạn còn gây lỗi làm mất chính xác bản kê hàng trong kho. Vì vậy, tất cả các truy vấn SQL để mua hàng phải được định nghĩa như là chỉ một hoạt động không chia cắt được.

Các bước trong một giao dịch

Bây giờ hãy xem các bước nào cần phải đưa vào trong một giao dịch DB2. Trước khi bạn bắt đầu, một kết nối phải được thiết lập với cơ sở dữ liệu mà giao dịch sẽ thi hành đối với nó.

Bắt đầu giao dịch với một câu lệnh có thể thi hành được. Một câu lệnh thi hành luôn luôn xảy ra với một giao dịch. Nếu một chương trình có chứa một câu lệnh thi hành được sau khi một giao dịch kết thúc, nó bắt đầu một giao dịch mới. Những câu lệnh tiếp theo đây là không thi hành được:

BEGIN DECLARE SECTION
END DECLARE SECTION
INCLUDE SQLCA
INCLUDE SQLDA
DECLARE CURSOR
WHENEVER

Kết thúc giao dịch theo cách sau đây:

COMMIT
ROLLBACK

Câu lệnh COMMIT kết thúc giao dịch và làm cho các thay đổi trở thành thấy được đối với các tiến trình khác. Hãy nhớ rằng, bạn nên thường xuyên cam kết và nhất là thực hiện điều này trước khi chấm dứt chương trình. DB2 tự động phục hồi các giao dịch nếu bạn không cam kết chúng tường minh trên các hệ điều hành Windows. Trên các hệ điều hành khác, DB2 cam kết tất cả các giao dịch treo chưa xử lý trong thời gian chấm dứt chương trình tự động.

Câu lệnh ROLLBACK (phục hồi lại) trả về cơ sở dữ liệu ở trạng thái mà nó đã có trước khi giao dịch được chạy. Rollback ngăn việc áp dụng các thay đổi cho cơ sở dữ liệu sau khi cam kết giao dịch cuối cùng. Điều này đảm bảo rằng hoặc tất cả các hoạt động trong giao dịch được cam kết hoặc không hoạt động nào được cam kết cả. DB2 phục hồi các thay đổi dưới các điều kiện sau đây:

  • Một điều kiện đầy bản ghi.
  • Một điều kiện hệ thống làm cho tiến trình hệ thống kết thúc.

Để tránh hỏng vòng lặp, hãy sử dụng WHENEVER SQLWARNING CONTINUE (tiếp tục mỗi khi có cảnh báo SQL) hay WHENEVER SQLERROR CONTINUE (tiếp tục mỗi có lỗi SQL) trước một câu lệnh ROLLBACK. Một câu lệnh ROLLBACK không có hiệu lực đối với các nội dung của các biến chủ.

Bạn nên chấm dứt ứng dụng của bạn bằng cách thực hiện theo các bước sau:

  • Kết thúc giao dịch hiện tại của bạn bằng lệnh COMMIT hoặc ROLLBACK.
  • Giải phóng kết nối của bạn bằng lệnh CONNECT RESET (khởi động lại kết nối).
  • Giải phóng các tài nguyên (chẳng hạn như lưu trữ tạm thời, các cấu trúc dữ liệu và bộ nhớ có chia sẻ).

Bạn có thể có nhiều giao dịch trong một ứng dụng. Trong một giao dịch, bạn có thể có nhiều kết nối tới cơ sở dữ liệu.

Các kết nối và các giao dịch

Các giao diện lập trình có hai loại kết nối: giao dịch và không giao dịch. Mặc dù DB2 hỗ trợ các khái niệm này, bạn nên lưu ý rằng thực sự chỉ có một kiểu kết nối tới cơ sở dữ liệu -- đó là kết nối giao dịch. Vì vậy, mọi truy vấn SQL là một phần của một giao dịch. Khi bạn chạy trong chế độ không giao dịch, giao diện lập trình mà bạn đang sử dụng đã bật cho phép một tính năng gọi là cam kết tự động (autocommit), nó đưa ra một câu lệnh COMMIT ngầm sau mỗi phép toán SQL. Bạn phải đảm bảo rằng không bật cho phép cam kết tự động nếu đơn vị công việc (UOW) của bạn có nhiều truy vấn.

Các điểm lưu trữ và các giao dịch

Một điểm lưu trữ (savepoint) là một cơ cấu để hồi lại (undo) một công việc đã được thực hiện bởi hệ thống quản lý cơ sở dữ liệu (DBMS) khi một yêu cầu cơ sở dữ liệu bị thất bại. Các điểm lưu trữ làm cho các yêu cầu xử lý cơ sở dữ liệu phân chia được (non-atomic) hoạt động theo cách không phân chia được (atomic). Nếu một lỗi xảy ra trong quá trình thi hành, điểm lưu trữ có thể được dùng để hồi lại các thay đổi được thực hiện bởi giao dịch từ thời điểm mà điểm lưu trữ bắt đầu đến thời điểm yêu cầu phục hồi về điểm lưu trữ.

Một điểm lưu trữ cho phép bạn nhóm một vài câu lệnh SQL thành chỉ một khối thi hành riêng lẻ. Trước khi thi hành câu lệnh con đầu tiên của khối, đòi hỏi phải có một yêu cầu khởi động điểm lưu trữ khối. Nếu một trong các câu lệnh con kết thúc bằng một lỗi, thì chỉ có câu lệnh con đó được cuộn lại. Điều này mang lại mức chi tiết mịn hơn so với câu lệnh SQL phức hợp, trong đó một lỗi làm cho toàn bộ khối kết thúc có lỗi và phục hồi toàn bộ câu lệnh SQL phức hợp. Tại cuối điểm lưu trữ khối các câu lệnh, bạn có thể hoặc giải phóng điểm lưu trữ này hay phục hồi tới điểm lưu trữ.

Bây giờ hãy xem xét một số câu lệnh SQL cho phép bạn tạo ra và kiểm soát các điểm lưu trữ . Để thiết lập một điểm lưu trữ, hãy đưa ra một câu lệnh SQL là SAVEPOINT Để làm cho mã lệnh của bạn rõ ràng hơn, bạn có thể chọn một tên có ý nghĩa cho điểm lưu trữ. Ví dụ:

SAVEPOINT SAVEPOINT1 ON ROLLBACK RETAIN CURSORS

Để giải phóng một điểm lưu trữ , hãy đưa ra câu lệnh SQL là RELEASE SAVEPOINT. Ví dụ:

RELEASE SAVEPOINT SAVEPOINT1

Nếu bạn không giải phóng dứt khoát một điểm lưu trữ bằng câu lệnh SQL là RELEASE SAVEPOINT, nó sẽ được giải phóng khi kết thúc giao dịch.

Để phục hồi lại một điểm lưu trữ , hãy đưa ra một câu lệnh SQL là ROLLBACK TO SAVEPOINT. Ví dụ:

ROLLBACK TO SAVEPOINT SAVEPOINT1

Làm việc với các đối tượng lớn

Một đối tượng lớn là gì?

Các đối tượng dữ liệu lớn, như các hình ảnh và âm thanh, thường xuyên cần phải được lưu giữ trong một cơ sở dữ liệu. DB2 cung cấp các kiểu dữ liệu chuyên dụng để lưu trữ các đối tượng dữ liệu lớn. Các kiểu dữ liệu này được biết đến như là các đối tượng lớn (LOBs). Trong phần này, bạn sẽ khám phá thế giới của các LOB. Với tư cách là một nhà phát triển, bạn cần có khả năng lưu trữ và lấy ra các LOB trong các ứng dụng của bạn.

DB2 cung cấp ba kiểu khác nhau của các kiểu dữ liệu LOB. Tất cả các kiểu dữ liệu này có thể chứa tới 2 gigabyte dữ liệu:

  • CLOB -- Chứa đến 2 gigabytes dữ liệu ký tự.
  • BLOB -- Chứa đến 2 gigabyte dữ liệu nhị phân. Dữ liệu nhị phân này có thể, về thực chất, là bất cứ thứ gì (ví dụ như một hình ảnh hoặc một tệp tin âm thanh).
  • Double-Byte Character Large Object (DBCLOB-Đối tượng lớn ký tự hai byte) -- Chứa đến 2 gigabytes dữ liệu ký tự hai byte. Lưu ý rằng kiểu dữ liệu này chỉ nên được sử dụng nếu cơ sở dữ liệu mà bạn đã tạo ra đã được cấu hình cho dữ liệu hai byte.
  • XML -- Chứa đến 2 gigabyte dữ liệu XML. XML không được trình bày trong hướng dẫn này, vì chúng được trình bày sau trong loạt bài này.

Các giá trị LOB không được lưu giữ trong một bảng cơ sở dữ liệu. Cái thực sự được lưu trữ là một cái mô tả (descriptor). Cái mô tả này trỏ đến vị trí thực tế của LOB. Các giá trị LOB thực sự được lưu trữ trong các vùng bảng (tablespaces). Các vùng bảng là các đơn vị lưu trữ vật lý. Cái thực sự được lưu trữ trong một cột LOB thực tế không phải là dữ liệu LOB, mà thực tế là một con trỏ (pointer) tới dữ liệu LOB. Con trỏ này được biết đến như một cái định vị ("locator"). Những cái định vị ấy được sử dụng để đại diện cho các giá trị LOB của bạn. Khi bạn lấy ra dữ liệu trong một ResultSet (tập kết quả), bạn sẽ lấy ra cái định vị chứ không phải là các giá trị LOB thực sự mà chúng đại diện. Bạn phải yêu cầu tường minh để nhận được các giá trị LOB cần lấy ra. Việc lấy ra này được gọi là "vật chất hóa".

Khi tạo một bảng, bạn có thể chỉ rõ tùy chọn COMPACT hoặc NOT COMPACT. Nếu lựa chọn COMPACT được xác định, thì dữ liệu LOB mà bạn lưu trữ chiếm một không gian lưu trữ tối thiểu. Tuy nhiên, nếu bạn thực hiện một cập nhật cột LOB mà làm tăng kích cỡ của LOB được lưu trữ, thì bạn phải trả giá về hiệu năng. Mặt khác, nếu bạn chỉ rõ NOT COMPACT (mặc định), các giá trị LOB của bạn về thực chất tự do gia tăng kích cỡ.

Nếu bạn chỉ rõ tùy chọn LOGGED, thế thì các cập nhật một cột LOB được ghi lại trong bản nhật ký hệ thống. Việc chỉ định rõ tùy chọn LOGGED cung cấp sự bảo vệ tốt nhất cho hầu hết các dữ liệu được lưu trữ, sao cho nó có thể được xây dựng lại trong trường hợp xảy ra lỗi phương tiện bằng một quá trình phục hồi thuận chiều. Tuy nhiên, điều này đi kèm với chi phí khi nói đến không gian đĩa (chưa đề cập đến các chi phí thời gian để ghi vào đĩa). Nếu bạn không chỉ định rõ một lựa chọn, thì tùy chọn LOGGED được chọn theo mặc định. Bây giờ hãy xem xét một số ví dụ bằng Java.

PREPAREDSTATEMENT PREPAREDSTATEMENT =  
      CONNECTION.PREPARESTATEMENT("INSERT INTO BOOKCOVERS VALUES(?,?)"); 
FILE IMAGEFILE = NEW FILE("C:\\REDBOOKCOVER.JPG"); 
INPUTSTREAM INPUTSTREAM = NEW FILEINPUTSTREAM(IMAGEFILE); 
PREPAREDSTATEMENT.SETSTRING(1," 0738425826"); 
PREPAREDSTATEMENT.SETBINARYSTREAM(2,INPUTSTREAM,(INT)(IMAGEFILE.LENGTH())); 
PREPAREDSTATEMENT.EXECUTEUPDATE();

Đoạn mã trên sẽ lấy một tệp tin có tên redbookcover.jpg nằm trong thư mục gốc của ổ đĩa C: và lưu trữ nó vào trong cơ sở dữ liệu. Lưu ý cách bạn kết hợp tệp tin của bạn với InputStream như thế nào. Đối tượng InputStream này được sử dụng để đặt giá trị của câu lệnh đã chuẩn bị đại diện cho cột BLOB của bạn.

PREPAREDSTATEMENT PREPAREDSTATEMENT = 
CONNECTION.PREPARESTATEMENT(
   "SELECT BOOKCOVER FROM BOOKCOVERS WHERE BOOKISBN=?"); 
PREPAREDSTATEMENT.SETSTRING(1, "0738425826"); 
RESULTSET RESULTSET = PREPAREDSTATEMENT.EXECUTEQUERY(); 
WHILE (RESULTSET.NEXT()) { 
	// MATERIALIZATION OF THE BLOB 
	BLOB BLOB = RESULTSET.GETBLOB(1); 
	INPUTSTREAM INPUTSTREAM = BLOB.GETBINARYSTREAM(); 
	FILE FILEOUTPUT = NEW 
	  FILE("C:\\CLONEDREDBOOKCOVER.JPG"); 
	FILEOUTPUTSTREAM FO = NEW
	  FILEOUTPUTSTREAM(FILEOUTPUT); 
	INT C; 
	WHILE ((C = INPUTSTREAM.READ()) != -1) 
	FO.WRITE(C); 
	FO.CLOSE(); 
	SYSTEM.OUT.PRINTLN("BLOB RETRIEVED");

Trong đoạn mã Java ở trên, một câu lệnh đã chuẩn bị đã được thi hành trong đó BLOB đã chèn vào cơ sở dữ liệu trong đoạn mã trước đó được chọn lấy ra. Điều quan trọng cần lưu ý là BLOB thực sự chưa được vật chất hóa cho đến dòng:

INPUTSTREAM INPUTSTREAM = BLOB.GETBINARYSTREAM();

Luồng đầu vào được sử dụng để lưu trữ BLOB đã lấy ra thành một tệp tin gọi là clonedredbookcover.jpg. Để lấy ra các CLOB, cú pháp tương tự với cú pháp để lấy ra một BLOB.

FILE FILEOUTPUT = ;NEW; 
  FILE("C:\\CLONEDREDBOOKABSTRACT.TXT"); 
FILEOUTPUTSTREAM FO = ;NEW; FILEOUTPUTSTREAM(FILEOUTPUT); 
INPUTSTREAM IS = CLOB.GETASCIISTREAM(); 
INT C; 
WHILE; ((C = IS.READ()) != -1) 
   FO.WRITE(C); 
FO.CLOSE();

Trong các đoạn mã Java ở trên, CLOB được lưu trữ đã được vật chất hóa thành một tệp tin mới có tên là clonedredbookabstract.txt. Điều này được thực hiện bằng cách sử dụng phương thức getAsciiStream của CLOB. Giống như khi bạn lấy ra các BLOB, bạn gán luồng đó vào một InputStream, mà nó sau đó được đọc ra và lần lượt ghi những gì đã đọc được tới FileOutputStream.


Kết luận

Tóm tắt

Trong hướng dẫn này, bạn học được rất nhiều khái niệm về các chiến lược thao tác dữ liệu. Bạn đã học làm thế nào để:

  • Truy cập dữ liệu trong nhiều bảng và thay đổi chúng.
  • Sử dụng các MQT.
  • Sử dụng các thường trình SQL.
  • Sử dụng các bảng chung.
  • Sử dụng các con trỏ.
  • Sử dụng kiểu dữ liệu CLOB và BLOB.
  • Lập trình với các giao dịch.

Trong khi hướng dẫn này tập trung vào các khái niệm, các hướng dẫn tiếp theo trong loạt bài này mô tả tất cả các giao diện được sử dụng để thực hiện thao tác dữ liệu.

Tài nguyên

Học tập

  • IBM DB2 Information Management Training and certification page: Tìm thêm các thông tin về kỳ thi lấy chứng chỉ Phát triển ứng dụng của họ DB2 9 (kỳ thi 733) cũng như các thông tin về các lớp, các chứng chỉ có sẵn và các tài nguyên bổ sung.
  • DB2 9 Application Development exam 733 prep tutorial series: Như đã đề cập ở trên, hướng dẫn này chỉ là một trong chín hướng dẫn được thiết kế để trợ giúp bạn chuẩn bị cho kỳ thi lấy chứng chỉ Phát triển ứng dụng của họ DB2 9 (kỳ thi 733). Danh sách đầy đủ của tất cả các hướng dẫn trong loạt này bao gồm:
    • Các đối tượng cơ sở dữ liệu và các phương pháp lập trình.
    • Thao tác dữ liệu.
    • Thao tác dữ liệu XML.
    • Lập trình SQL nhúng.
    • Lập trình ODBC/CLI.
    • Lập trình .NET.
    • Lập trình Java.
    • Lập trình nâng cao.
    • Các thường trình do người dùng định nghĩa.
  • DB2 9 Fundamentals certification prep tutorial series: Trước khi bạn tham dự kỳ thi lấy chứng chỉ Phát triển ứng dụng DB2 9 (kỳ thi 733), bạn cần phải đã tham dự và vượt qua kỳ thi lấy chứng chỉ cơ sở DB2 9 (kỳ thi 730). Hãy sử dụng loạt bài gồm bảy hướng dẫn này để chuẩn bị cho kỳ thi đó; các chủ đề bao gồm:
    • Lập kế hoạch DB2.
    • An ninh DB2.
    • Truy cập dữ liệu DB2.
    • Làm việc với dữ liệu DB2.
    • Làm việc với các đối tượng DB2.
    • Tương tranh dữ liệu.
    • Giới thiệu Xquery.
  • DB2 V9 Database administration certification prep series: Chuẩn bị cho kỳ thi lấy chứng chỉ quản trị cơ sở dữ liệu DB2 9 dành cho Linux, UNIX và Windows (kỳ thi 731). Một tập hợp bảy hướng dẫn trình bày các chủ đề sau đây:
    • Quản lý máy chủ.
    • Việc bố trí dữ liệu.
    • Truy cập cơ sở dữ liệu.
    • Giám sát hoạt động DB2.
    • Các tiện ích DB2.
    • Tính sẵn sàng cao: Sao lưu và phục hồi.
    • Tính sẵn sàng cao: Nhân bản phân chia và khắc phục sự cố có tính sẵn sàng cao (HADR).
  • DB2 Information Center: Tìm hiểu thêm về thao tác dữ liệu. Đặc biệt xem xét các phần sau đây:
    • Tài liệu tham khảo và hướng dẫn CLI phiên bản DB2 9, Phần 1. Đặc biệt chú ý Chương 5: Các con trỏ.
    • Tài liệu hướng dẫn SQL phiên bản DB2 9, Tập 2. Phần này trình bày các câu lệnh SQL có liên quan đến Các con trỏ.
    • Hướng dẫn phát triển ứng dụng phiên bản DB2 9: Lập trình các ứng dụng khách. Phần này trình bày các con trỏ trong các môi trường lập trình khác nhau.
  • Ngoài ra, xem các chương trình mẫu có sẵn kèm với DB2. Các chương trình này được gởi đi trong thư mục sqllib/samples, với các thư mục con dành cho C, Java và các ngôn ngữ khác.
  • developerWorks resource page for DB2 for Linux, UNIX, and Windows: Tìm các bài viết và các hướng dẫn và kết nối đến tài nguyên khác để mở rộng các kỹ năng DB2 của bạn.
  • Tìm hiểu thêm về DB2 Express-C, một phiên bản miễn phí của Ấn bản DB2 Express dành cho cộng đồng.
  • Theo sát với các sự kiện kỹ thuật và Webcasts của developerWorks.
  • developerWorks Information Management zone: Tìm hiểu thêm về DB2. Tìm tài liệu hướng dẫn kỹ thuật, các bài báo hướng dẫn, giáo dục, tải về, thông tin sản phẩm và nhiều hơn nữa.

Lấy sản phẩm và công nghệ

  • Tải về một phiên bản dùng thử miễn phí DB2 Enterprise 9.
  • DB2 Express-C: Bây giờ bạn có thể sử dụng DB2 miễn phí. Tải xuống miễn phí Ấn bản DB2 Express dành cho cộng đồng, có cung cấp cùng các tính năng cốt lõi như DB2 Express Edition và cung cấp một cơ sở vững chắc để xây dựng và triển khai các ứng dụng.
  • Xây dựng dự án phát triển tiếp theo của bạn với phần mềm dùng thử IBM, có sẵn để tải về trực tiếp từ developerWorks.

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Information Management
ArticleID=431528
ArticleTitle=Chuẩn bị cho kỳ thi 733 về Phát triển ứng dụng DB2 9, Phần 2: Thao tác dữ liệu DB2
publish-date=09252009