Giới thiệu

SQL là ba ký tự viết tắt của cụm từ Structured Query Language (ngôn ngữ truy vấn có cấu trúc).

SQL là một ngôn ngữ chuẩn dành cho việc truy cập và thao tác cơ sở dữ liệu (DataBase - DB).

SQL là một chuẩn ANSI (American National Standards Institute).

SQL có thể làm được:

  • Tạo cơ sở dữ liệu
  • Truy xuất dữ liệu (data) từ cơ sở dữ liệu
  • Tạo bảng (TABLE) trong cơ sở dữ liệu
  • Chèn các bản ghi (record) vào bảng
  • Cập nhật (UPDATE) các bản ghi
  • Xem (SELECT) các bản ghi
  • Xoá (DELETE) bản ghi
  • Tạo chỉ mục (index)
  • Tạo khung nhìn (view)
  • Tạo thủ tục lưu trữ (Stored Procedure) trong cơ sở dữ liệu
  • Tạo TRIGGER
  • Thiết lập các quyền trên bảng, view, thủ tục lưu trữ, ...
  • Thiết lập các điều kiện thông qua If ... Else, CASE ... WHEN.
  • ....

Tiền thân của SQL là SEQUEL, là một ngôn ngữ được IBM phát triển và sử dụng trong hệ cơ sở dữ liệu thử nghiệm có tên là System/R vào năm 1974, chính thức được ANSI/ISO công nhận là một chuẩn ngôn ngữ sử dụng trong cơ sở dữ liệu quan hệ vào năm 1986. Cho đến hiện nay, SQL đã được sử dụng phổ biển trong các hệ quản trị cơ sở dữ liệu thương mại và có vai trò quan trọng trong những hệ thống này.

Ngôn ngữ truy vấn có cấu trúc (SQL) và các hệ quản trị cơ sở dữ liệu quan hệ là một trong những nền tảng kỹ thuật quan trọng trong công nghiệp máy tính. Cho đến nay, có thể nói rằng SQL đã được xem là ngôn ngữ chuẩn trong cơ sở dữ liệu. Các hệ quản trị cơ sở dữ liệu quan hệ thương mại hiện có như Oracle, SQL  Server, Informix, DB2,... đều chọn SQL làm ngôn ngữ cho sản phẩm của mình.

Vậy thực sự SQL là gì? Tại sao nó lại quan trọng trong các hệ quản trị cơ sở dữ liệu? SQL có thể làm được những gì và như thế nào? Nó được sử dụng ra sao trong các hệ quản trị cơ sở dữ liệu quan hệ? Nội dung của chương này sẽ cung cấp cho chúng ta cái nhìn tổng quan về SQL và một số vấn đề liên quan.

SQL là ngôn ngữ cơ sở dữ liệu quan hệ

SQL là công cụ sử dụng để tổ chức, quản lý và truy xuất dữ liệu đuợc lưu trữ trong các cơ sở dữ liệu. SQL là một hệ thống ngôn ngữ bao gồm tập các câu lệnh sử dụng để tương tác với cơ sở dữ liệu quan hệ.

 Tên gọi ngôn ngữ truy vấn có cấu trúc phần nào làm chúng ta liên tưởng đến một công cụ (ngôn ngữ) dùng để truy xuất dữ liệu trong các cơ sở dữ liệu. Thực sự mà nói, khả năng của SQL vượt xa so với một công cụ truy xuất dữ liệu, mặc dù đây là mục đích ban đầu khi SQL được xây dựng nên và  truy xuất dữ liệu vẫn còn là một trong những chức năng quan trọng của nó.

SQL được sử dụng để điều khiển tất cả các chức năng mà một hệ quản trị cơ sở dữ liệu cung cấp cho người dùng bao gồm:

•  Định nghĩa dữ liệu: SQL cung cấp khả năng định nghĩa các cơ sở dữ liệu, các cấu trúc lưu trữ và tổ chức dữ liệu cũng như mối quan hệ giữa các thành phần dữ liệu.

•  Truy xuất và thao tác dữ liệu: Với SQL, người dùng có thể dễ dàng thực hiện các thao tác truy xuất, bổ sung, cập nhật và loại bỏ dữ liệu trong các cơ sở dữ liệu.

•  Điều khiển truy cập: SQL có thể được sử dụng để cấp phát và kiểm soát các thao tác của người sử dụng trên dữ liệu, đảm bảo sự an toàn cho cơ sở dữ liệu.

•  Đảm bảo toàn vẹn dữ liệu: SQL định nghĩa các ràng buộc toàn vẹn trong cơ sở dữ liệu nhờ đó đảm bảo tính hợp lệ và chính xác của dữ liệu trước các thao tác cập nhật cũng như các lỗi của hệ thống.

Như vậy,  có thể nói rằng SQL là một ngôn ngữ hoàn thiện được sử dụng trong các hệ thống cơ sở dữ liệu và là một thành phần không thể thiếu trong các hệ quản trị cơ sở dữ liệu. Mặc dù SQL không phải là một ngôn ngữ lập trình như C, C++, Java,... song các câu lệnh mà SQL cung cấp có thể được nhúng vào trong các ngôn ngữ lập trình nhằm xây dựng các ứng dụng tương tác với cơ sở dữ liệu.

Khác với các ngôn ngữ lập trình quen thuộc như C, C++, Java,... SQL là ngôn ngữ có tính khai báo.

Với SQL, người dùng chỉ cần mô tả các yêu cầu cần phải thực hiện trên cơ sở dữ liệu mà không cần phải chỉ ra cách thức thực hiện các yêu cầu như thế nào. Chính vì vậy, SQL là ngôn ngữ dễ tiếp cận và dễ sử dụng.

Vai trò của SQL

Bản thân SQL không phải là một hệ quản trị cơ sở dữ liệu, nó không thể tồn tại độc lập. SQL thực sự là một phần của hệ quản trị cơ sở dữ liệu, nó xuất hiện trong các hệ quản trị cơ sở dữ liệu với vai trò ngôn ngữ và là công cụ giao tiếp giữa người sử dụng và hệ quản trị cơ sở dữ liệu. 

 Trong hầu hết các hệ quản trị cơ sở dữ liệu quan hệ, SQL có những vai trò như sau:

•  SQL là ngôn ngữ truy vấn có tính tương tác: Người sử dụng có thể dễ dàng thông qua các trình tiện ích để gởi các yêu cầu dưới dạng các câu lệnh SQL đến cơ sở dữ liệu và nhận kết quả trả về từ cơ sở dữ liệu 

•  SQL là ngôn ngữ lập trình cơ sở dữ liệu: Các lập trình viên có thể nhúng các câu lệnh SQL vào trong các ngôn ngữ  lập trình để xây dựng nên các chương trình ứng dụng giao tiếp với cơ sở dữ liệu.

•  SQL là ngôn ngữ quản trị cơ sở dữ liệu: Thông qua SQL, người quản trị cơ sở dữ liệu có thể quản lý được cơ sở dữ liệu, định nghĩa các cấu trúc lưu trữ dữ liệu, điều khiển truy cập cơ sở dữ liệu,...

•  SQL là ngôn ngữ cho các hệ thống khách/chủ (client/server): Trong các hệ thống cơ sở dữ liệu khách/chủ, SQL được sử dụng như là công cụ để giao tiếp giữa các trình ứng dụng phía máy khách với máy chủ cơ sở dữ liệu.

•  SQL là ngôn ngữ truy cập dữ liệu trên Internet: Cho đến nay, hầu hết các máy chủ Web cũng như các máy chủ trên Internet sử dụng SQL với vai trò là ngôn ngữ để tương tác với dữ liệu trong các cơ sở dữ liệu.

•  SQL là ngôn ngữ cơ sở dữ liệu phân tán: Đối với các hệ quản trị cơ sở dữ liệu phân tán, mỗi một hệ thống sử dụng SQL để giao tiếp với các hệ thống khác trên mạng, gởi và nhận các yêu cầu truy xuất dữ liệu với nhau.

Quy tắc chung

SQL không phân biệt hoa và thường, ví dụ A và a là như nhau. Vậy nên bạn có thể tự do viết các câu lệnh SQL mà không cần để ý đến dạng hoa thường của ký tự.

Có một số RDBMS yêu cầu kết thúc câu lệnh phải có dấu ';' , tuy nhiên một số khác lại không yêu cầu, ví dụ như SQL Server của Microsoft.

Một câu lệnh SQL có thể được đăt trên nhiều hàng.

Muốn thực thi lệnh hay lô lệnh nào ta bôi đen câu lệnh hay khối lệnh đó rồi nhấn nút thực thi (trong SQL Server bạn có thể nhấn phím F5 trên bàn phím để thực thi).

Giữa các lệnh trong lô lệnh nên đặt mệnh đề (go).

Những công việc cần làm để có một cơ sở dữ liệu:

a) Tạo một database bằng câu lệnh: create database

b) Tạo các bảng cho database đã tạo ở bước a)

c) Thiết lập các ràng buộc (constraint) khóa chính (Primary Key - PK) và khóa ngoại liên kết (Foreign Key - FK)

d) Thiết lập các ràng buộc khác theo yêu cầu cụ thể như: default, unique, check, ...

e) Chèn (INSERT) dữ liệu vào các bảng theo thứ tự bảng chứa PK trước, bảng chứa FK sau.

Một số câu lệnh phổ biến trong SQL:
  • SELECT - truy xuất/lấy dữ liệu từ database
  • UPDATE - cập nhật dữ liệu
  • DELETE - xoá dữ liệu
  • INSERT INTO hoặc INSERT - chèn dữ liệu vào bảng
  • CREATE DATABASE - tạo cơ sở dữ liệu
  • ALTER DATABASE - sửa cơ sở dữ liệu
  • CREATE TABLE - tạo bảng
  • ALTER TABLE - sửa bảng
  • DROP TABLE - xoá bảng
  • CREATE INDEX - tạo chỉ mục (search key)
  • DROP INDEX - xoá chỉ mục
  • ...

Xem video hướng dẫn cài đặt SQL Server 2012 tại đây: Hướng dẫn cài đặt SQL Server 2012

Quy tắc đặt tên

Sau đây là những quy tắc cần nhớ khi đặt tên cho cơ sở sở dữ liệu, tên bảng, tên cột:

1. Tên không được có số ở đầu. Ví dụ 1st, 2ab, 3xyz, ... là sai.

2. Tên được phép chứa dấu cách, nhưng phải đặt trong cặp []. Ví dụ như [ho ten], [ngày sinh], [db sinh viên], [môn học] ... là hợp lệ.

3. Tên được phép có chứa ký tự có dấu. Ví dụ như họtên, ngàysinh, dbsinhviên, mônhọc, ... là hợp lệ.

4. Tên được phép trùng với từ khóa, nhưng cần đặt trong cặp []. Ví dụ như [order], [subject], [table], [date], ... đều hợp lệ.

5. Tên không được chứa dấu '@' ở đầu, vì dấu '@' thể hiện cho biến.

6. Tên không được chứa dấu '$' ở đầu.

7. Tên không được chứa phép toán. Ví dụ, n*m, !m, a/b, ... là sai.

Thao tác với DataBase

1. Tạo cơ sở dữ liệu:

Để tạo một cơ sở dữ liệu ta dùng cú pháp như sau:

CREATE DATABASE Tên_DB;

Ví dụ:

CREATE DATABASE dbStudent;

2. Sửa cơ sở dữ liệu:

Cú pháp:

ALTER DATABASE Tên_DB <Tuỳ chọn các thao tác>;

Ví dụ:

ALTER DATABASE dbStudent MODIFY NAME=Studentdb;

3. Sử dụng database:

Cú pháp:

USE Tên_DB;

Ví dụ:

USE dbStudent;

4. Xoá database:

Lưu ý: Muốn xoá database hiện thời cần phải chuyển sử dụng database khác, ví dụ như master (là một db sẵn có).

Cú pháp:

DROP DATABASE Tên_DB;

Ví dụ:

DROP DATABASE dbStudent;

Nếu hiện tại dbStudent đang được dùng đến thì không thể xoá, trong trường hợp này ta sẽ làm như sau:

USE master;

DROP DATABASE dbStudent;

Video demo: Create, alter, use and drop DataBase (DB)

 

Kiểu dữ liệu hệ thống

Kiểu dữ liệu dùng để định nghĩa loại giá trị có thể lưu trữ cho một cột nào đó của bảng.

Dưới đây là danh sách các kiểu dữ liệu hệ thống (được xây dựng sẵn) phổ biến:

Mục

Kiểu dữ liệu

Mô tả

Số chính xác

int

Một cột được khai báo kiểu dữ liệu này sẽ sử dụng 4 byte trong bộ nhớ máy tính. Nó thường được sử dụng để lưu trữ giá trị số nguyên.

smallint

Một cột được khai báo kiểu dữ liệu này sẽ sử dụng 2 byte trong bộ nhớ máy tính. Nó có thể lưu trữ các số nguyên từ -32768 đến 32767.

tinyint

Một cột của kiểu này chiếm 1 byte trong bộ nhớ. Có giá trị từ 0 đến 255

bigint  

Một cột được khai báo kiểu dữ liệu này sẽ sử dụng 8 byte trong bộ nhớ máy tính. Nó có thể lưu trữ các số nguyên từ -2^63 (-9.223.372.036.854.775.808) đến 2^63-1

numeric

Một cột được khai báo kiểu dữ liệu này sẽ có độ chính xác cao và có thể co dãn kích thước lưu trữ trong bộ nhớ.

money

Một cột được khai báo kiểu dữ liệu này sẽ sử dụng 8 byte trong bộ nhớ máy tính. Biểu diễn giá trị dữ liệu tiền tệ từ (-2^63/10000) đến (2^63-1).

 

Mục

Kiểu dữ liệu

Mô tả

Số xấp xỉ (Approximate)

float

Một cột được khai báo kiểu dữ liệu này sẽ sử dụng 8 byte trong bộ nhớ máy tính. Biễu diễn các số chấm động từ -1.79E+308 đến 1.79E+308.

real

Một cột được khai báo kiểu dữ liệu này sẽ sử dụng 4 byte trong bộ nhớ máy tính. Biễu diễn các số chấm động có độ chính xác từ -3.4E+38 đến 3.40E+38.


Date and time

datetime

Biễu diễn ngày và giờ. Được lưu trữ như là 2 số integer, chiếm 8 byte.

smalldatetime

Biễu diễn ngày và giờ. Được lưu trữ như là 2 số integer, chiếm 4 byte.

date

Chỉ biễu diễn ngày.

 

Mục

Kiểu dữ liệu

Mô tả

Chuỗi ký tự không dấu

char(n)

Lưu trữ dữ liệu ký tự với kích thước cố định và không hỗ trợ Unicode (không lưu được dữ liệu có dấu). Để dễ hình dung hơn có kiểu dữ liệu này, ta ví dụ như n=20, tức là char(20) và điều này có nghĩa là cột của bảng có kiểu này có thể lưu trữ được những chuỗi không dấu lên đến tối đa 20 ký tự. Nếu ta có một chuỗi là 'SQL Server 2014', chuỗi này gồm 15 ký tự, khi đó vì còn thừa 5 ký tự (20-15=5) nên hệ thống sẽ tự động thêm vào sau chuỗi tương ứng năm dấu cách cho đủ 20. Điều này có nghĩa rằng dữ liệu lưu trữ trong cột có kiểu char(20) sẽ luôn luôn có kích thước là 20.

varchar(n)

Cũng lưu trữ dữ liệu ký tự nhưng với kích thước thay đổi theo thực tế của dữ liệu và kích thước tối đa là n ký tự và không hỗ trợ Unicode.

text

Lưu trữ dữ liệu ký tự, độ dài có thể thay đổi và không hỗ trợ Unicode. Nó thường được dùng để lưu trữ văn bản có kích thước lớn, như mô tả sản phẩm chẳng hạn.

Chuỗi ký tự có dấu (unicode)

nchar(n)

Lưu trữ dữ liệu kí tự, nó được cố định kích thước và có hỗ trợ Unicode.

nvarchar(n)

Lưu trữ dữ liệu kí tự, độ dài có thể thay đổi và có hỗ trợ Unicode.

 

Mục

Kiểu dữ liệu

Mô tả

Một số kiểu dữ liệu khác

timestamp

Một cột được khai báo kiểu dữ liệu này sẽ sử dụng 8 byte trong bộ nhớ máy tính. Nó chứa các số binary tự động phát sinh (mỗi hàng là một số duy nhất).

binary(n)

Lưu trữ dữ liệu binary có độ đài cố định với độ dài tối đa là 8000byte.

varbinary(n)

Lưu trữ dữ liệu binary có độ đài thay đổi với độ dài tối đa là 8000byte. .

image

 Lưu trữ dữ liệu binary có độ đài thay đổi với độ dài tối đa là (2^30-1) byte.

uniqueidentifier

Một cột được khai báo kiểu dữ liệu này sẽ sử dụng 16 byte trong bộ nhớ máy tính. Ngoài ra nó lưu trữ một GUID (Globally Unique Identifier). Cấu trúc của mã GUID có dạng theo hệ 16: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, ví dụ: 72A07EF0-6BB8-4AEF-B2FF-6C5C7D3439D8. Bạn có thể dùng hàm NEWID() để tạo giá trị này một cách tự động.

Kiểu dữ liệu tự tạo

Đây là kiểu dữ liệu do người dùng tạo ra dựa trên các kiểu dữ liệu có sẵn.

Sử dụng câu lệnh CREATE TYPE để tạo.

Cú pháp:

CREATE TYPE Tên_kiểu_mới FROM Kiểu_có_sẵn [Tùy chọn khác];

Ví dụ:

CREATE TYPE string40 FROM nvarchar(40) NOT NULL; --Tạo kiểu string40 chứa dữ liệu có dấu, kích thước tối đa 40 và không được để trống

CREATE TABLE Bảng1(

...

hoten string40,

...

);

CREATE TABLE bang2(

...

tenmonhoc string40,

...

);

Comment (Chú thích)

SQL có hai loại chú thích.

Chú thích trên một dòng:

Sử dụng hai dấu '-' đặt liên tục nhau: --

Ví dụ:

--Đây là chú thích: tạo một cơ sở dữ liệu

create database dbStudent;

Chú thích trên nhiều dòng:

Sử dụng cặp: /*...*/

Ví dụ:

/*

Tạo cơ sở dữ liệu lưu trữ

các thông tin sinh viên

*/

create database dbStudent;

NULL và NOT NULL

Đặc trưng của khả năng Null của một cột quyết định các hàng trong bảng có thể chứa một giá trị Null cho cột đó.

Khả năng Null của một cột có thể được định nghĩa khi tạo một bảng hoặc định dạng một bảng.

Từ khóa NULL được sử dụng để chỉ ra rằng giá trị null là được phép trong cột.

Nếu bạn không sử dụng từ khóa NULL để chỉ định cho cột được phép Null thì hệ thống sẽ mặc định cột đó được phép lưu trữ NULL.

Từ khóa NOT NULL được sử dụng để chỉ ra rằng giá trị null là không được phép.

Ví dụ:

CREATE TABLE StoreDetails(
  StoreID int NOT NULL,
  Name varchar(40) NULL
);

Identity & Auto_increment

1. Thuộc tính IDENTITY

IDENTITY hay còn gọi là thuộc tính nhận dạng của SQL Server được sử dụng để tạo ra cột nhận dạng, chúng chứa các giá trị tự động phát sinh tuần tự để nhận dạng duy nhất mỗi hàng trong một bảng.

Mỗi một bảng chỉ được phép có duy nhất một thuộc tính nhận dạng.

Một thuộc tính nhận dạng có hai thành phần:

  • Giá trị khởi đầu (seed value)
  • Giá trị tăng (increment value) hay còn gọi là bước nhảy

Cú pháp:

IDENTITY(seed_value, increment_value)

Cần nhớ rằng nếu viết là identity mà không có phần seed_value và increment_value thì tương đương: identity(1,1).

Ví dụ:

identity(1,1) nghĩa là giá trị khởi đầu là 1 và các giá trị sẽ được tự động tạo ra là 1, 2, 3, ...

identity(3,5) nghĩa là giá trị khởi đầu là 3 và các giá trị sẽ được tự động tạo ra là 3, 8, 13, ...

Ví dụ áp dụng vào thực tế:

CREATE TABLE Student(
  studentid int IDENTITY NOT NULL,
  studentname nvarchar(30)
);

, cột studentid sẽ tự động nhận các giá trị bắt đầu từ 1 và các giá trị sau là 2, 3, 4, ...

Lưu ý:

+ Bạn không thể chỉnh sửa (UPDATE) được các giá trị của cột đặt IDENTITY.

+ Do các giá trị của cột đặt IDENTITY là tự động được sinh ra trong quá trình chèn (INSERT) bản ghi, nên nếu bạn muốn chủ động đặt giá trị tại cột này trong quá trình chèn bản ghi bạn cần thực hiện như sau:

SET IDENTITY_INSERT Tên_bảng ON;

INSERT Tên_bảng(Các_cột) values(Các_giá_trị);

Ví dụ:

SET IDENTITY_INSERT Student ON;
INSERT Student(studentid, studentname) values(13,'ABCD');

2. Thuộc tính AUTO_INCREMENT

AUTO_INCREMENT có ý nghĩa tương tự như IDENTITY nhưng được sử dụng trong MySQL.

Lưu ý là AUTO_INCREMENT chỉ thiết lập giá trị khởi đầu là 1 và bước nhảy là 1 cho mỗi bản ghi mới chèn vào.

MySQL chop phép sửa đổi giá trị của cột AUTO_INCREMENT một cách tuỳ ý mà không cần có yêu cầu chỉnh sửa nào.

Ví dụ:

CREATE TABLE Persons(
  ID int NOT NULL AUTO_INCREMENT,
  LastName varchar(255) NOT NULL,
  FirstName varchar(255),
  [Address] varchar(255),
  City varchar(255),
  PRIMARY KEY (ID)
);

CREATE TABLE (Tạo bảng)

Bảng là một cấu trúc gồm các cột và hàng.

Mỗi cột của bảng gọi là trường hay thuộc tính.

Mỗi hàng của bảng là một bản ghi đại diện cho thực thể trong thực tế.

Để tạo bảng trong cơ sở dữ liệu ta dùng câu lệnh CREATE TABLE.

Cú pháp:

CREATE TABLE Tên_bảng(

  Tên_cột1 Kiểu_dữ_liệu [Tuỳ chọn],

  Tên_cột2 Kiểu_dữ_liệu [Tuỳ chọn],

  ...

);

Ví dụ:

--Tạo bảng Subjects chứa các môn học
CREATE TABLE Subjects(
  subjectid int not null,
  subjectname nvarchar(40)
);
 
--Tạo bảng Marks chứa điểm của sinh viên
CREATE TABLE Marks(
  studentid int not null,
  subjectid int not null,
  mark real
);

Xem video hướng dẫn tạo bảng (Create Table) tại đây: Tạo bảng (Create Table)

Thao tác với bảng (TABLE)

1. Tạo bảng (CREATE TABLE)

Bảng là một cấu trúc gồm các cột và hàng, mỗi cột của bảng gọi là trường hay thuộc tính, mỗi hàng của bảng là một bản ghi đại diện cho thực thể trong thực tế.

Để tạo bảng trong cơ sở dữ liệu ta dùng câu lệnh CREATE TABLE. Cú pháp của việc tạo bảng như sau:

CREATE TABLE Tên_bảng(
  Tên_cột1 Kiểu_dữ_liệu [Tuỳ chọn],
  Tên_cột2 Kiểu_dữ_liệu [Tuỳ chọn],
  ...
);

Đoạn mã dưới đây tạo ra ba bảng trong cơ sở dữ liệu có tên dbDemo.

use dbDemo;
--Tạo bảng Student chứa thông tin sinh viên
CREATE TABLE Student(
  studentid int not null identity,
  studentname nvarchar(30),
  dateofbrith date
);
--Tạo bảng Subjects chứa các môn học
CREATE TABLE Subjects(
  subjectid int not null,
  subjectname nvarchar(40)
);
--Tạo bảng Marks chứa điểm của sinh viên
CREATE TABLE Marks(
  studentid int not null,
  subjectid int not null,
  mark real
);

2. Sửa bảng (ALTER TABLE)

Để sửa một bảng nào đó của cơ sở dữ liệu thì ta sử dụng câu lệnh ALTER TABLE. Các thao tác sửa bảng có thể có gồm thêm cột, sửa cột và xóa cột.

2.1. Thêm cột

Trong trường hợp ta muốn có thêm cột dữ liệu cho bảng để nó chứa dữ liệu phù hợp với thực tế thì ta có thể thêm cột vào bảng đó. Cú pháp pháp của việc thêm cột là như sau:

ALTER TABLE Tên_bảng ADD Tên_cột Kiểu_dữ_liệu [Tuỳ_chọn_khác];

Ví dụ dưới đây sẽ thêm một cột có tên là gender vào bảng Student:

ALTER TABLE Student ADD gender bit not null default(1);

2.2. Sửa cột

Nếu cột nào đó của bảng đang có kiểu dữ liệu không đáp ứng được thực tế hoặc bạn cần thêm hoặc sửa một vài tùy chọn khác cho cột thì ta sử dụng cú pháp sau đây để tiến hành sửa cột cho bảng:

ALTER TABLE Tên_bảng ALTER COLUMN Tên_cột Kiểu_dữ_liệu [Tuỳ_chọn_khác];

Ví dụ sau sẽ sửa cột gender trong đó nó sẽ nhận giá trị mặc định là 0:

ALTER TABLE Student ALTER COLUMN gender bit not null default(0);

Giả sử trong quá trình tạo bảng bạn đặt tên nhầm cho cột nào đó, thì nếu bạn muốn sửa tên của cột đó bạn có thể sử dụng cú pháp sau:

exec sp_rename 'Tên_bảng.Tên_cột_cần_sửa','Tên_cột_mới';

Đoạn mã sau tiến hành đổi tên cột là gender của bảng Student thành tên mới là gioi_tính:

exec sp_rename 'Student.gender','gioi_tinh';

2.3. Xoá cột

Trường hợp bạn thấy cột nào đó của bảng đang chứa dữ liệu không cần thiết hoặc cột đó đó tồn tại trong bảng nhưng không chứ bất kỳ dữ liệu nào, thì bạn có thể xóa nó. Cú pháp để xóa một như sau:

ALTER TABLE Student DROP COLUMN Tên_cột_cần_xoá;

Đoạn mã dưới đây tiến hành xóa cột gender của bảng Student:

ALTER TABLE Student DROP COLUMN gender;

Lưu ý khi xoá cột:

+ Không xoá được cột chứa PK. Nếu muốn xoá phải huỷ ràng buộc PK trước, mà muốn huỷ ràng buộc PK phải huỷ ràng buộc FK liên kết tới.

+ Không xoá được cột chứa FK. Nếu muốn xoá phải huỷ ràng buộc FK trước.

3. Xoá bảng

Nếu bạn muốn xoá một bảng hoặc nhiều bảng một lúc khỏi cơ sở dữ liệu thì bạn dùng câu lệnh: DROP TABLE. Ví dụ:

DROP TABLE Student, Marks; --xoá hai bảng Student và Marks

Thao tác với cột (Column)

1. Thêm cột:

Cú pháp SQL Server:

ALTER TABLE Tên_bảng ADD Tên_cột Kiểu_dữ_liệu [Tuỳ_chọn_khác];

Ví dụ:

ALTER TABLE Student ADD gender bit not null default(1);

Cú pháp MySQL:

ALTER TABLE Tên_bảng ADD Tên_cột Kiểu_dữ_liệu [Tuỳ_chọn_khác];

Ví dụ:

ALTER TABLE Student ADD Status varchar(10) not null default 'Young';

2. Sửa cột:

Cú pháp:

ALTER TABLE Tên_bảng ALTER COLUMN Tên_cột Kiểu_dữ_liệu [Tuỳ_chọn_khác];

Ví dụ:

ALTER TABLE Student ALTER COLUMN gender bit not null default(0);

Sửa tên cột:

Cú pháp:

exec sp_rename ‘Tên_bảng.Tên_cột_cần_sửa’,’Tên_cột_mới’;

Ví dụ:

exec sp_rename ‘Student.gender’,’gioi_tinh’;

3. Xoá cột:

Cú pháp:

ALTER TABLE Student DROP COLUMN Tên_cột_cần_xoá;

Ví dụ:

ALTER TABLE Student DROP COLUMN gender;

Lưu ý khi xoá cột:

+ Không xoá được cột chứa PK. Nếu muốn xoá phải huỷ ràng buộc PK trước, mà muốn huỷ ràng buộc PK phải huỷ ràng buộc FK liên kết tới.

+ Không xoá được cột chứa FK. Nếu muốn xoá phải huỷ ràng buộc FK trước.

Primary Key (Khóa chính)

Ràng buộc khoá chính (PRIMARY KEY - PK) được dùng để phân biệt các bản ghi trong một bảng. PK đảm bảo tính toàn vẹn thực thể cho bảng. PK được đặt trên một cột hoặc một tập cột của bảng. Cột đặt PK thông thường là cột mã như mã sinh viên, mã môn học, mã sản phẩm, ...

Dưới đây là một số điểm bạn cần lưu ý khi sử dụng PK:

- Một bảng chỉ được phép có duy nhất một PK.

- Muốn đặt PK trên cột thì cột đó không được chứa những giá trị giống nhau và phải là cột NOT NULL. Ví dụ các mã sinh viên là khác nhau nên có thể đặt PK trên cột mã sinh viên.

- Muốn đặt PK trên một tập cột thì tập cột đó không được chứa những tập giá trị giống nhau và mỗi cột của tập cột đó phải là cột NOT NULL. Ví dụ bảng điểm sinh viên có mã sinh viên và mã môn học thì tập giá trị của tập cột (mã sinh viên,mã môn học) là khác nhau nên có thể đặt PK trên tập cột này.

- Không thể chèn bản ghi mà giá trị tại cột chứa khoá chính đã có từ trước. Ví dụ như với bảng Customer đã có bản ghi có mã khách (CustomerID) là 5 rồi thì ta không thêm được khách hàng có mã là 5 nữa. Hình dưới đây minh hoạ điều này.

sql: minh hoạ primary key

Để tạo ràng buộc PK ta có các cách được thể hiện thông qua các ví dụ như sau đây.

Cách 1:

CREATE TABLE Student(
studentid int not null PRIMARY KEY, --đặt PK ngay sau khi tạo cột tương ứng
studentname nvarchar(30),
dateofbirth date
);

Cách 2:

CREATE TABLE Student(
studentid int not null,
studentname nvarchar(30),
dateofbirth date,
PRIMARY KEY(studentid) --đặt PK phía cuối các phần tạo cột
);

Cách 3:

CREATE TABLE Student(
studentid int not null,
studentname nvarchar(30),
dateofbirth date,
constraint pk_studentid PRIMARY KEY(studentid) --tạo một ràng buộc PK trong bảng
);

Cách 4:

Ở cách này ta sử dụng biện pháp sửa bảng để thêm khóa chính vào. Cú pháp cụ thể được thể hiện như dưới đây:

ALTER TABLE Tên_bảng ADD PRIMARY KEY(Tên_cột); --tạo PK sau khi đã tạo xong bảng

Ví dụ:

ALTER TABLE Student ADD PRIMARY KEY(studentid);
ALTER TABLE Marks ADD PRIMARY KEY(studentid,subjectid);

Cách 5:

Cách này sẽ tạo một ràng buộc khóa chính cho bảng tương ứng. Cách này được sử dụng khi bạn muốn tách biệt hẳn câu lệnh thuần tạo bảng với câu lệnh tạo khóa chính, đồng thời cách này cũng cho phép bạn có thể dễ dàng thay đổi khóa chính cho bảng khi cần. Cú pháp của cách này là như sau:

ALTER TABLE Tên_bảng ADD CONSTRAINT Tên_ràng_buộc PRIMARY KEY(Tên_cột); --tạo một ràng buộc PK có tên riêng (đây là cách khuyên dùng khi muốn điều chỉnh lại PK)

Ví dụ:

ALTER TABLE Student ADD CONSTRAINT pk_student PRIMARY KEY(studentid);
ALTER TABLE Marks ADD CONSTRAINT pk_marks PRIMARY KEY(studentid,subjectid);

Foreign Key (Khoá ngoại)

Ràng buộc khóa ngoại (Foreign Key - FK) được sử dụng để liên kết các bảng dữ liệu trong một cơ sở dữ liệu.

FK đảm bảo toàn vẹn tham chiếu cho bảng.

FK được đặt trên một cột, nó chỉ đến (hay tham chiếu đến) khóa chính trong một bảng khác.

Giả sử có hai bảng A và B, bảng A có cột a và bảng B có cột b. Muốn thiết lập liên kết giữa hai bảng A và B thông qua hai cột a và b thì:

- Nếu đặt FK trên cột a thì cột b phải là cột PK hoặc ngược lại, nếu đặt FK trên cột b thì cột a phải là cột PK.

- Kiểu dữ liệu của hai cột a và b phải giống nhau.

- Cột đặt FK phải chứa những giá trị giống với những giá trị của cột đặt PK. Ví dụ cột a của bảng A là cột PK và chứa hai giá trị 1 và 2 thì cột b của bảng B cũng chỉ chứa những giá trị 1 và 2 mà không được chứa nhưng giá trị khác.

Tạo ràng buộc FK:

Giả sử ta tạo bảng Student như sau:

CREATE TABLE Student(

studentid int not null identity,

studentname nvarchar(30),

dateofbirth date,

constraint pk_student PRIMARY KEY(studentid)

);

Bây giờ ta tạo bảng Marks và tạo ràng buộc FK trên cột studentid của bảng Marks tham chiếu đến cột studentid của bảng Student, ta sẽ có các cách tạo FK như sau:

Cách 1: Ví dụ:

CREATE TABLE Marks(

studentid int not null FOREIGN KEY REFERENCES Student(studentid),

subjectid int not null,

mark float,

constraint pk_marks primary key(studentid,subjectid)

);

Cách 2: Ví dụ:

CREATE TABLE Marks(

studentid int not null,

subjectid int not null,

mark float,

constraint pk_marks primary key(studentid,subjectid),

FOREIGN KEY(studentid) REFERENCES Student(studentid)

);

Cách 3: Ví dụ:

CREATE TABLE Marks(

studentid int not null,

subjectid int not null,

mark float,

constraint pk_marks primary key(studentid,subjectid),

constraint fk_studentid FOREIGN KEY(studentid) REFERENCES Student(studentid)

);

Cách 4: Sử dụng cú pháp như sau:

ALTER TABLE Tên_bảng1 ADD FOREIGN KEY(Tên_cột_đặt_FK) REFERENCES Tên_bảng2(Tên_cột_đặt_PK);

Ví dụ:

CREATE TABLE Marks(

studentid int not null,

subjectid int not null,

mark float,

constraint pk_marks primary key(studentid,subjectid),

);

ALTER TABLE Marks ADD FOREIGN KEY(studentid) REFERENCES Student(studentid);

Cách 5: Ta sử dụng cú pháp như sau:

ALTER TABLE Tên_bảng1 ADD CONSTRAINT Tên_ràng_buộc FOREIGN KEY(Tên_cột_đặt_FK) REFERENCES Tên_bảng2(Tên_cột_đặt_PK);

Ví dụ:

CREATE TABLE Marks(

studentid int not null,

subjectid int not null,

mark float,

constraint pk_marks primary key(studentid,subjectid),

);

ALTER TABLE Marks ADD CONSTRAINT fk_studentid FOREIGN KEY(studentid) REFERENCES Student(studentid);

Ràng buộc CHECK

Ràng buộc kiểm tra (CHECK) dùng để giới hạn giá trị dữ liệu nhập vào trong cột.

Ví dụ, cột điểm của sinh viên chỉ lưu trữ các điểm số trong đoạn [0-25]. Để đảm bảo điều này bạn sử dụng ràng buộc CHECK để giới hạn giá trị nhập vào cột điểm của sinh viên chỉ trong đoạn [0-25] thì người dùng sẽ không thể nhập những giá trị nằm ngoài vùng này.

Ràng buộc CHECK đảm bảo toàn vẹn dữ liệu.

Nếu bạn đặt ràng buộc CHECK trên một cột thì nó sẽ giới hạn giá trị chỉ cho cột đó.

Nhưng nếu bạn đặt ràng buộc CHECK trên bảng thì nó có thể giới hạn giá trị cho nhiều cột của bảng đó.

Để tạo ràng buộc CHECK ta có các cách sau:

Cách 1: Được thể hiện ở ví dụ sau:

CREATE TABLE Marks(

studentid int not null,

subjectid int not null,

datetest date,

mark float CHECK(mark between 0 and 25)

);

Cách 2: Được thể hiện ở ví dụ sau:

CREATE TABLE Marks(

studentid int not null,

subjectid int not null,

datetest date,

mark float,

CHECK(mark between 0 and 25 and datetest>='2010/01/01')

);

Cách 3: Được thể hiện ở ví dụ sau:

CREATE TABLE Marks(

studentid int not null,

subjectid int not null,

datetest date,

mark float,

constraint ck_mark_datetest CHECK(mark between 0 and 25 and datetest>='2010/01/01')

);

Cách 4: Sử dụng cú pháp sau:

ALTER TABLE Tên_bảng ADD CHECK(Điều_kiện);

Ví dụ:

ALTER TABLE Student ADD CHECK(mark between 0 and 25 and datetest>='2010/01/01');

Cách 5: Sử dụng cú pháp sau:

ALTER TABLE Tên_bảng ADD CONSTRAINT Tên_ràng_buộc CHECK(Điều_kiện);

Ví dụ:

ALTER TABLE Student ADD CONSTRAINT ck_mark_datetest CHECK(mark between 0 and 25 and datetest>='2010/01/01');

Ràng buộc DEFAULT

Ràng buộc mặc định (DEFAULT) được dùng để gán giá trị mặc định cho cột nếu giá trị của cột đó không được đưa vào khi chèn bản ghi vào bảng.

Mỗi bảng có thể có nhiều ràng buộc DEFAULT.

Mỗi cột của bảng chỉ có một ràng buộc DEFAULT.

Lưu ý: DEFAULT không thể được tạo trên cột đã được định nghĩa với:

  • Kiểu dữ liệu timestamp
  • Thuộc tính IDENTITY hoặc ROWGUIDCOL
  • Đã tồn tại ràng buộc DEFAULT hoặc đối tượng DEFAULT.

Dưới đây là một số cách áp dụng ràng buộc DEFAULT:

Cách 1: ​Ví dụ (ví dụ này áp dụng cho hầu hết các RDBMS như MySQL, SQL Server, Oracle, MS Access):

CREATE TABLE Student(

studentid int NOT NULL,

studentname nvarchar(30) NOT NULL,

dateofbirth date NOT NULL DEFAULT('1997-01-10')

);

INSERT Student(studentid, studentame) VALUES(1,N'Nguyễn Văn A')

Ở ví dụ trên cột dateofbirth không được chèn giá trị khi chèn bản ghi vào bảng Student, nên trong trường hợp này cột sẽ được đặt giá trị mặc định là '1997-01-01'.

Cách 2: Sử dụng câu lệnh ALTER TABLE như sau:

+ Áp dụng cho MySQL, ví dụ:

ALTER TABLE Student ALTER Price SET DEFAULT('1997-01-01');

+ Áp dụng cho MS Access, ví dụ:

ALTER TABLE Student ALTER COLUMN Price SET DEFAULT('1997-01-01');

Cách 3: Áp dụng cho SQL Server, sử dụng cú pháp như sau:

ALTER TABLE Tên_bảng ADD CONSTRAINT Tên_ràng_buộc DEFAULT(Giá_trị) FOR Tên_cột;

Ví dụ:

ALTER TABLE Student ADD CONSTRAINT df_student_dob DEFAULT('1997-01-01') FOR dateofbirth

Ràng buộc UNIQUE

Ràng buộc UNIQUE

Ràng buộc khóa duy nhất (UNIQUE) được sử dụng để bảo đảm rằng chỉ các giá trị duy nhất được nhập vào trong cột hoặc một tập hợp các cột. Nó cho phép nhà phát triển chắc chắn rằng không có các giá trị trùng lặp được nhập vào.

Ví dụ, mỗi một sinh viên có một email riêng không giống các email khác. Để đảm bảo điều này thì cột lưu email của sinh viên nên đặt ràng buộc UNIQUE.

Ràng buộc khóa chính (Primary Key) chính là thể hiện của ràng buộc UNIQUE.

Ràng buộc UNIQUE đảm bảo toàn vẹn thực thể cho bảng bởi vì khi nó được áp dụng sẽ không thể có hai hàng trong bảng có thể có cùng một giá trị đối với cột đặt ràng buộc UNIQUE.

Một bảng có thể có nhiều ràng buộc UNIQUE.

Ràng buộc UNIQUE có thể đặt trên một cột hoặc môt tập cột.

Cột đặt ràng buộc UNIQUE có thể lưu trữ giá trị NULL nhưng chỉ lưu trữ được duy nhất một lần, có nghĩa trong cột đó không được lưu trữ hai giá trị NULL.

Để tạo ràng buộc UNIQUE ta có các cách sau:

Cách 1: Được thể hiện ở ví dụ sau:

CREATE TABLE Student(
studentid int not null primary key,
studentname nvarchar(30),
dateofbirth date,
email varchar(50) UNIQUE
);

Cách 2: Được thể hiện ở ví dụ sau:

CREATE TABLE Student(
studentid int not null primary key,
studentname nvarchar(30),
dateofbirth date,
email varchar(50),
UNIQUE(email)
);

Cách 3: Được thể hiện ở ví dụ sau:

CREATE TABLE Student(
studentid int not null primary key,
studentname nvarchar(30),
dateofbirth date,
email varchar(50),
constraint un_email UNIQUE(email)
);

Cách 4: Sử dụng cú pháp sau:

ALTER TABLE Tên_bảng ADD UNIQUE(Các_cột);

Ví dụ:

ALTER TABLE Student ADD UNIQUE(email);

Cách 5: Sử dụng cú pháp sau:

ALTER TABLE Tên_bảng ADD CONSTRAINT Tên_ràng_buộc UNIQUE(Các_cột);

Ví dụ:

ALTER TABLE Student ADD CONSTRAINT un_email UNIQUE(email);

INSERT

INSERT (hay INSERT INTO) được dùng để chèn các bản ghi vào bảng. Dưới đây là một số lưu ý khi dùng INSERT:

+ Bạn nên chèn dữ liệu vào bảng chứa PK trước, FK sau nếu hai bảng có mối liên kết với nhau.

+ Nếu đặt IDENTITY (hoặc AUTO_INCREMENT đối với MySQL) cho cột nào thì không được chèn dữ liệu vào cột đó.

+ Nếu dữ liệu là chuỗi hoặc ngày tháng thì cần đặt vào cặp nháy đơn ‘’. Ví dụ ‘Nguyen Van A’, ’2010-01-01’.

+ Nếu dữ liệu là chuỗi có dấu thì cần đặt tiền tố N trước cặp nháy đơn. Ví dụ N’Nguyễn Văn A’.

+ Nếu dữ liệu là ngày tháng thì chỉ được sử dụng một trong hai dạng ‘yyyy-mm-dd’ hoặc ‘mm-dd-yyyy’.

+ Trong trường hợp muốn chèn dữ liệu ngày tháng có dạng ‘dd-mm-yyyy’ thì cần sử dụng câu lệnh sau trước khi chèn: SET DATEFORMAT dmy;

Có ba lựa chọn cho câu lệnh INSERT. Tùy thuộc vào thực tế mà bạn sử dụng lựa chọn cho phù hợp. Dưới đây ta sẽ tìm hiểu về ba lựa chọn này.

Lựa chọn 1

Lựa chọn này dùng để chèn bản ghi vào tất cả các cột của bảng theo thứ tự cột đầu tiên chèn Giá_trị1, cột thứ hai chèn Giá_trị2, và vân vân.

Cú pháp:

INSERT Tên_bảng VALUES(Giá_trị1, Giá_trị2,…);

Ví dụ: Bảng Student có 3 cột là studentid kiểu int, studentname kiểu nvarchar(30) và cột dateofbirth kiểu date thì ta sẽ chèn dữ liệu như sau:

INSERT Student VALUES(1,N'Nguyễn Văn A', '1996-05-20');

Lựa chọn 2

Lựa chọn này dùng để chèn bản ghi vào những cột mong muốn.

Cú pháp:

INSERT Tên_bảng(Cột1, Cột2,…) VALUES(Giá_trị1, Giá_trị2,…);

Lưu ý:

+ Bắt buộc phải chèn dữ liệu vào cột chứa ràng buộc PK nếu cột này không áp dụng IDENTITY (hoặc AUTO_INCREMENT đối với MySQL).

+ Vì không được chèn dữ liệu vào cột IDENTITY, nên Lựa chọn 2 sẽ được sử dụng mà không thể sử dụng Lựa chọn 1.

Ví dụ:

+ Nếu cột studentid đặt ràng buộc PK mà không áp dụng IDENTITY (hoặc AUTO_INCREMENT đối với MySQL):

INSERT Student(studentid, studentname) VALUES(1, N'Nguyễn Văn A');

+ Nếu cột studentid đặt ràng buộc PK và áp dụng IDENTITY (hoặc AUTO_INCREMENT đối với MySQL):

INSERT Student(studentname, dateofbirth) VALUES(N'Nguyễn Văn A' , '1996-05-20');

, khi đó bảng Student sẽ nhận được thêm một bản ghi trong đó cột studentid sẽ nhận được giá trị mà IDENTITY tự sinh ra.

Lựa chọn 3

Lựa chọn này cho phép chèn cùng lúc nhiều bản ghi vào bảng.

Cú pháp:

INSERT Tên_bảng VALUES(Các_giá_trị1), (Các_giá_trị2), (Các_giá_trị3),...;
Hoặc:
INSERT Tên_bảng(Các_cột) VALUES(Các_giá_trị1), (Các_giá_trị2), (Các_giá_trị3),...;

Ví dụ:

INSERT Student VALUES(1, N'Nguyễn Văn A', '1996-05-20'), (2, N'Đặng Văn B', '1997-05-21'), (3, N'Trần Văn C', '1998-05-22');

Ví dụ trên sẽ chèn cùng lúc 3 bản ghi vào bảng Student.

INSERT với SELECT

Câu lệnh INSERT với SELECT dùng để chèn dữ liệu vào bảng bằng cách lấy dữ liệu từ bảng hoặc các bảng khác.

Giả sử ta tạo một bảng có tên Student1 để lưu những sinh viên có năm sinh từ 1997 về trước của bảng Student:

CREATE TABLE Student1(

studentid int,

studentname nvarchar(30),

dateofbirth date

);

Có hai lựa chọn áp dụng câu lệnh INSERT với SELECT như sau:

Lựa chọn 1:

Cú pháp:

INSERT Tên_bảng SELECT * FROM Tên_bảng1,Tên_bảng2,...;

Hoặc:

INSERT Tên_bảng SELECT Các_cột FROM Tên_bảng1,Tên_bảng2,...;

Ví dụ:

INSERT Student1 SELECT * FROM Student WHERE datepart(year,dateofbirth)<=1997;

Lựa chọn 2:

INSERT Tên_bảng(Các_cột) SELECT * FROM Tên_bảng1,Tên_bảng2,...;

Hoặc:

INSERT Tên_bảng(Các_cột) SELECT Các_cột FROM Tên_bảng1,Tên_bảng2,...;

Ví dụ:

INSERT Student1(studentname,dateofbirth) SELECT studentname,dateofbirth FROM Student WHERE datepart(year,dateofbirth)<=1997;

SELECT

Tổng quan

Câu lệnh SELECT được xem là câu lệnh nền tảng dùng để truy cập dữ liệu trong SQL. Đầu ra của câu lệnh SELECT là một tập kết quả được thể hiện dưới dạng một bảng ảo.

Câu lệnh SELECT trong một truy vấn sẽ hiển thị thông tin cần thiết trong bảng, nó sẽ lấy dữ liệu trên các hàng và cột từ một hoặc nhiều bảng.

SELECT còn nối hai bảng hoặc lấy một tập hợp con các cột từ một hoặc nhiều bảng. Nó cũng cho phép định nghĩa các cột được sử dụng cho một truy vấn. Cú pháp của SELECT có thể bao gồm một loạt các biểu thức cách nhau bằng dấu phẩy. Mỗi biểu thức trong câu lệnh sẽ là một cột trong tập kết quả. Các cột sẽ xuất hiện trong tập kết quả theo cùng một trình tự giống như thứ tự của biểu thức tương ứng trong câu lệnh truy vấn.

SELECT lấy các hàng từ cơ sở dữ liệu và cho phép lựa chọn một hoặc nhiều hàng hoặc cột từ một bảng. Dưới đây ta sẽ tìm hiểu các cú pháp khác nhau của câu lệnh SELECT.

SELECT không có FROM

Kể từ phiên bản SQL Server 2005 trở đi thì bạn có thể sử dụng SELECT mà không cần phải sử dụng mệnh đề FROM. Dưới đây là một số ví dụ thể hiện:

SELECT LEFT(N'Việt Nam',4); --Lấy 4 ký tự đầu tiên của chuỗi
SELECT RIGHT(N'Việt Nam',3); --Lấy 3 ký tự cuối của chuỗi
SELECT N'Môn học SQL', GETDATE(); --Hiển thị chuỗi có dấu và ngày tháng hiện thời

Giải thích:

Hàm LEFT() có tác dụng lấy 4 ký tự bên trái của chuỗi tương ứng, hàm RIGHT() lấy 3 ký tự bên phải chuỗi, hàm GETDATE() dùng để lấy ngày tháng và thời gian hiện tại, trong đó phần thời gian là giây được lấy với độ chính xác 3 con số.

Hiển thị tất cả các cột

Nếu bạn muốn hiển thị tất cả các cột của bảng thì bạn dùng dấu (*). Dấu này được dùng như một cách viết tắt để liệt kê toàn bộ các cột của bảng tương ứng trong mệnh đề FROM.

Cú pháp:

SELECT * FROM Tên_bảng;
Hoặc:
SELECT Tên_bảng.* FROM Tên_bảng;

, trong đó, Tên_bảng là tên của bảng mà bạn muốn lấy thông tin. Bạn có thể đưa vào số lượng bảng tuỳ ý, khi đó ta dùng dấu (,) để phân cách giữa các bảng. Có lưu ý là khi hai hoặc nhiều bảng được sử dụng thì hàng của môi bảng sẽ được ánh xạ với hàng của các bảng khác, và hoạt động này sẽ dân đến tốn rất nhiều thời gian truy xuất. Lời khuyên ở đây là bạn nên sử dụng cú pháp này kèm theo một điều kiện (sử dụng mệnh đề WHERE).

Ví dụ: Giả sử bạn muốn lấy thông tin của toàn bộ bảng Customer thì bạn làm như sau:

SELECT * FROM Costomer; --hoặc SELECT Costomer.* FROM Costomer;

Hiển thị các cột mong muốn

Nếu bạn chỉ muốn hiện thị những cột mà bạn muốn của bảng thôi thì bạn sử dụng cú pháp sau đây để thực hiện.

Cú pháp:

SELECT Các_cột FROM Tên bảng;

Ví dụ: Bạn chỉ muốn hiển thị cột Name (tên) và cột Gender (giới tính) của bảng Customer thôi thì bạn làm như sau:

SELECT name,gender FROM Customer;

Nối chuỗi trong tập kết quả

Trong tập kết quả bạn có thể nối các chuỗi để có được kết quả hiển thị thân thiện hoặc dễ hiểu hơn. Bạn sử dụng phép toán '+' để ghép nối chuỗi.

Lưu ý là khi ghép chuỗi với cột có kiểu không phải chuỗi thì bạn cần chuyển sang kiểu chuỗi đối với cột đó bằng cách dùng hàm sau: STR(Tên_cột).

Ví dụ:

select N'Mã khách hàng:' + STR(Customerid) + N', Họ và tên: ' + Name from Customer;

Tính giá trị trong tập kết quả

Trong tập kết quả hiển thị bạn cũng có thể tính giá trị của các cột (có kiểu số) bằng các phép toán như +, -, *, /, ... Ví dụ:

SELECT Mark,Mark*0.12 AS N'Điểm thưởng' FROM Marks;

SELECT với AS (Alias - Bí danh)

Câu lệnh SELECT dùng để hiển thị dữ liệu trong đó các cột hiển thị sẽ được đặt bí danh hay tên riêng. Bí danh có thể là từ khoá, chứa ký tự có dấu, dấu cách cũng như các ký tự bất kỳ khác. Việc đặt bí danh sẽ giúp người dùng quan sát kết quả được dễ hiểu hơn và dữ liệu có được cũng trở nên có ý nghĩa hơn khi hiển thị.

Nếu bí danh có dấu cách hoặc chứa ký tự có dấu thì nên đặt trong cặp ngoặc vuông hoặc cặp nháy đơn, ví dụ như [Mã sinh viên], N'Họ và tên'. Nếu bí danh đặt trong cặp nháy đơn có chứa ký tự có dấu thì cần đặt tiền tố N phía trước cặp nháy đơn.

Có hai cách đặt bí danh cho cột:

Cách 1: Sử dụng AS

SELECT Cột1 AS Bí_danh1, Cột2 AS Bí_danh2, ... FROM Tên_bảng;

Ví dụ:

SELECT studentid AS [Mã sinh viên], studentname AS N'Họ và tên', dateofbirth AS N'Ngày sinh' FROM Student.

Cách 2: Bỏ qua AS

SELECT Cột1 Bí_danh1, Cột2 Bí_danh2, ... FROM Tên_bảng;

Ví dụ:

SELECT studentid [Mã sinh viên], studentname N'Họ và tên', dateofbirth N'Ngày sinh' FROM Student.

Sử dụng mệnh đề DISTINCT

DISTINCT dùng để lấy một bản ghi trong những bản ghi giống nhau trong tập kết quả. Trong tập kết quả nếu có nhiều bản ghi (hàng dữ liệu) giống hệt nhau thì DISTINCT sẽ chỉ lấy lại một bản ghi trong những bản ghi giống nhau đó. Hay nói cách khác là DISTINCT sẽ ngăn chặn việc lấy ra các bản ghi trùng lặp.

Cú pháp:

SELECT DISTINCT <phần câu lệnh tiếp theo>;

Lưu ý rằng DISTINCT phải nằm ngay sau SELECT.

Ví dụ:

SELECT DISTINCT studentname FROM Student;

Kết quả của câu lệnh này là chỉ có một bản ghi sinh viên duy nhất được hiển thị, cho dùng bảng Student có thể có nhiều sinh viên trùng tên.

SELECT với JOIN

Loại câu lệnh này dùng để lấy dữ liệu từ hai bảng có liên quan hoặc liên kết với nhau. Ví dụ, bảng Student chứa thông tin sinh viên, bảng Marks chứa điểm sinh viên, hai bảng này có cột chung là studentid. Vậy nếu muốn biết các sinh viên có điểm số như thế nào thì cần sử dụng JOIN trong câu lệnh SELECT.

Cú pháp lấy tất cả các cột của hai bảng

SELECT * FROM Bảng1 Bí_danh1 JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung;

Ví dụ:

SELECT * FROM Student a JOIN Marks b ON a.studentid=b.studentid;

Cú pháp lấy một số cột từ hai bảng

SELECT Các_cột FROM Bảng1 Bí_danh1 JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung;

Ví dụ:

SELECT studentname,mark FROM Student a JOIN Marks b ON a.studentid=b.studentid;

Nếu trong Các_cột mà có cột nào có tên trùng nhau ở cả hai bảng thì cần phải nói rõ cột đó là của bảng nào bằng cú pháp:

Bí_danh.Cột_chung

Ví dụ cột studentid đều nằm ở cả hai bảng thì nếu muốn lấy cột studentid trong tập kết quả ta làm như sau:

SELECT a.studentid,studentname,mark FROM Student a JOIN Marks b ON a.studentid=b.studentid;

SELECT với nhiều JOIN

Câu lệnh SELECT với nhiều JOIN dùng để lấy dữ liệu từ ba bảng dữ liệu có liên quan hoặc liên kết với nhau trở lên.

Ví dụ bảng Student chứa thông tin sinh viên, bảng Marks chứa điểm sinh viên và bảng Subjects chứa môn học, thì nếu muốn biết các sinh viên có điểm số của mỗi môn học như thế nào ta cần sử dụng nhiều JOIN trong câu lệnh SELECT.

Cú pháp:

- Lấy tất cả các cột của các bảng

SELECT * FROM Bảng1 Bí_danh1 JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung JOIN Bảng3 Bí_danh3 ON Bí_danh2.Cột_chung1=Bí_danh3.Cột_chung1;

Ví dụ:

SELECT * FROM Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subjects c ON b.subjectid=c.subjectid;

- Lấy một số cột từ các bảng

SELECT Các_cột FROM Bảng1 Bí_danh1 JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung JOIN Bảng3 Bí_danh3 ON Bí_danh2.Cột_chung1=Bí_danh3.Cột_chung1;

Ví dụ:

SELECT studentname,subjectname,mark FROM Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subjects c ON b.subjectid=c.subjectid;

Ví dụ cột studentid đều nằm ở hai bảng Student và Marks và cột subjectid đều nằm ở hai bảng Marks và Subjects thì nếu muốn lấy cột studentid và subjectid trong tập kết quả ta làm như sau:

SELECT a.studentid,studentname,c.subjectid,subjectname,mark FROM Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subject c on b.subjectid=c.subjectid;

SELECT với INTO

Cú pháp:

SELECT Các_cột INTO Tên_bảng_mới FROM Các_bảng_liên_kết [where Điều_kiện];

Ý nghĩa:

Dùng để tạo một bảng mới có tên là Tên_bảng_mới, trong đó các cột của bảng mới chính là Các_cột, còn các hàng dữ liệu của bảng mới chính là tập kết quả có được qua câu lệnh SELECT. Ví dụ:

SELECT a.studentid, studentname, subjectname, mark INTO Student8 from Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subjects c ON b.subjectid=c.subjectid WHERE mark>=8;

Câu lệnh trên sẽ tạo ra một bảng mới có tên Student8, bảng này có các cột là studentid, studentname, subjectname và mark; các hàng của bảng Student8 chính là tập kết quả của câu lệnh SELECT.

SELECT với AS (Alias)

Câu lệnh SELECT với AS (bí danh) dùng để hiển thị dữ liệu trong đó các cột được hiển thị sẽ được đặt một bí danh.

Bạn có thể tùy ý đặt bí danh cho cột. Bí danh có thể là từ khoá, chứa ký tự có dấu, dấu cách cũng như các ký tự khác.

Nếu bí danh có dấu cách hoặc chứa ký tự có dấu thì nên đặt trong cặp ngoặc vuông hoặc cặp nháy đơn. Ví dụ [Mã sinh viên], N'Họ và tên'.

Nếu bí danh đặt trong cặp nháy đơn có chứa ký tự có dấu thì cần đặt tiền tố N phía trước cặp nháy đơn.

Có hai cách đặt bí danh cho cột:

Cách 1: Sử dụng AS

SELECT Cột1 AS Bí_danh1, Cột2 AS Bí_danh2, ... FROM Tên_bảng;

Ví dụ:

SELECT studentid AS [Mã sinh viên], studentname AS N'Họ và tên', dateofbirth AS N'Ngày sinh' FROM Student.


Cách 2: Không sử dụng AS

SELECT Cột1 Bí_danh1, Cột2 Bí_danh2, ... FROM Tên_bảng;

Ví dụ:

SELECT studentid [Mã sinh viên], studentname N'Họ và tên', dateofbirth N'Ngày sinh' FROM Student.

SELECT với JOIN

Câu lệnh SELECT với JOIN (INNER JOIN)  dùng để lấy dữ liệu từ hai bảng có liên quan hoặc liên kết với nhau.

Ví dụ bảng Student chứa thông tin sinh viên, bảng Marks chứa điểm sinh viên, hai bảng này có cột chung là studentid. Vậy nếu muốn biết các sinh viên có điểm số như thế nào thì cần sử dụng JOIN trong câu lệnh SELECT.

Cú pháp:

- Lấy tất cả các cột của hai bảng

SELECT * FROM Bảng1 Bí_danh1 JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung;

Ví dụ:

SELECT * FROM Student a JOIN Marks b ON a.studentid=b.studentid;


- Lấy một số cột từ hai bảng

SELECT Các_cột FROM Bảng1 Bí_danh1 JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung;

Ví dụ:

SELECT studentname,mark FROM Student a JOIN Marks b ON a.studentid=b.studentid;

Nếu trong Các_cột mà có cột nào có tên trùng nhau ở cả hai bảng thì cần phải nói rõ cột đó là của bảng nào bằng cú pháp:

Bí_danh.Cột_chung

Ví dụ cột studentid đều nằm ở cả hai bảng thì nếu muốn lấy cột studentid trong tập kết quả ta làm như sau:

SELECT a.studentid,studentname,mark FROM Student a JOIN Marks b ON a.studentid=b.studentid;

Hàm tập hợp (Aggregate)

Các hàm tập hợp được dùng để thống kê dữ liệu, các hàm này thường đi cùng với câu lệnh SELECT. Dưới đây là danh sách các hàm tập hợp phổ biến.

1. SUM()

Hàm SUM() dùng để tính tổng các giá trị của một cột nào đó.

Cú pháp:

SUM(Tên_cột)

Ví dụ áp dụng:

SELECT SUM(mark) AS N'Tổng điểm' FROM Marks;

Câu lệnh trên sẽ tính tổng tất cả các giá trị trong cột mark của bảng Marks.

- Tính tổng tuổi của các học viên (ý 8 bài tập Practical 2):

SELECT SUM(Age) AS N'Tổng tuổi của các học viên' FROM Student;

2. AVG()

Hàm AVG() dùng để tính tổng các giá trị của một cột nào đó.

Cú pháp:

AVG(Tên_cột)

Ví dụ áp dụng:

SELECT AVG(mark) AS N'Điểm trung bình' FROM Marks;

Câu lệnh trên sẽ tính trung bình cộng các giá trị trong cột mark của bảng Marks.

- Đưa ra tuổi trung bình của các học viên (ý 1 bài tập Practical 2):

SELECT AVG(Age) AS N'Tuổi trung bình của các học viên' FROM Student;

3. COUNT()

Hàm COUNT() dùng để đếm số bản ghi lấy được từ câu lệnh SELECT.

Cú pháp:

COUNT(* hoặc Tên_cột)

Ví dụ áp dụng:

SELECT COUNT(*) AS N'Số lượng bản ghi' FROM Marks;

Câu lệnh trên sẽ đếm các bản ghi của bảng Marks.

4. MAX()

Hàm MAX() dùng để lấy giá trị lớn nhất của một cột nào đó.

Cú pháp:

MAX(Tên_cột)

Ví dụ áp dụng:

SELECT MAX(mark) AS N'Điểm lớn nhất' FROM Marks;

Câu lệnh trên sẽ lấy giá trị lớn nhất trong cột mark của bảng Marks.

- Hiển thị điểm thi cao nhất của từng môn học (ý 18 bài tập Practical 2):

SELECT Name, MAX(Mark) AS N'Điểm thi cao nhất' FROM Test a JOIN StudentTest b on a.TestID = b.TestID GROUP BY Name;

5. MIN()

Ngược với hàm MAX(), hàm MIN() dùng để lấy giá trị nhỏ nhất của một cột nào đó.

Cú pháp:

MIN(Tên_cột)

Ví dụ áp dụng:

SELECT MIN(mark) AS N'Điểm nhỏ nhất' FROM Marks;

Câu lệnh trên sẽ lấy giá trị nhỏ nhất trong cột mark của bảng Marks.

- Hiển thị tên và điểm trung bình của những học viên có điểm trung bình nhỏ nhất (ý 17 bài tập Practical 2):

SELECT TOP(1) WITH TIES Name, AVG(Mark) AS N'Điểm trung bình' FROM Student a JOIN StudentTest b on a.StudentID = b.StudentID GROUP BY Name ORDER BY AVG(Mark);

SELECT với nhiều JOIN

Câu lệnh SELECT với nhiều JOIN dùng để lấy dữ liệu từ ba bảng dữ liệu có liên quan hoặc liên kết với nhau trở lên.

Ví dụ bảng Student chứa thông tin sinh viên, bảng Marks chứa điểm sinh viên và bảng Subjects chứa môn học, thì nếu muốn biết các sinh viên có điểm số của mỗi môn học như thế nào ta cần sử dụng nhiều JOIN trong câu lệnh SELECT.

Cú pháp:

- Lấy tất cả các cột của các bảng

SELECT * FROM Bảng1 Bí_danh1 JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung JOIN Bảng3 Bí_danh3 ON Bí_danh2.Cột_chung1=Bí_danh3.Cột_chung1;

Ví dụ:

SELECT * FROM Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subjects c ON b.subjectid=c.subjectid;


- Lấy một số cột từ các bảng

SELECT Các_cột FROM Bảng1 Bí_danh1 JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung JOIN Bảng3 Bí_danh3 ON Bí_danh2.Cột_chung1=Bí_danh3.Cột_chung1;

Ví dụ:

SELECT studentname,subjectname,mark FROM Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subjects c ON b.subjectid=c.subjectid;

Nếu trong Các_cột mà có cột nào có tên trùng nhau ở nhiều bảng thì cần phải nói rõ cột đó là của bảng nào bằng cú pháp:

Bí_danh.Cột_chung

Ví dụ cột studentid đều nằm ở hai bảng Student và Marks và cột subjectid đều nằm ở hai bảng Marks và Subjects thì nếu muốn lấy cột studentid và subjectid trong tập kết quả ta làm như sau:

SELECT a.studentid,studentname,c.subjectid,subjectname,mark FROM Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subject c on b.subjectid=c.subjectid;

Hàm Convert()

Hàm CONVERT() được dùng để chuyển đổi kiểu dữ liệu trong quá trình truy vấn với câu lệnh SELECT.

Cột được chuyển đổi kiểu sẽ hiển thị dữ liệu theo kiểu tương ứng đã được chuyển bởi hàm CONVERT().

Cú pháp:

CONVERT(Kiểu_dữ_liệu,Tên_cột)

Lưu ý:

+ Kiểu dữ liệu gốc của cột không thay đổi vì CONVERT() không có tác dụng sửa kiểu dữ liệu cho cột.

+ Hàm CONVERT() chỉ áp dụng cho SQL SERVER.

Ví dụ áp dụng:

SELECT studentname,subjectname,CONVERT(numeric(4,2),mark) AS [Điểm] FROM Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subjects c ON b.subjectid=c.subjectid;

Câu lệnh trên sẽ hiển thị các giá trị ở cột mark của bảng Student theo dạng số có 4 chữ số và độ chính xác của mỗi giá trị là 2.

Hàm ngày tháng

Các hàm ngày tháng được dùng để lấy thông tin về ngày, tháng cũng như năm.

Các hàm này thường đi cùng với câu lệnh SELECT.

DATEPART được hiểu là một phần giá trị của ngày tháng năm. Dưới đây là một danh sách các DATEPART:

Datepart

Tên viết tắt

Giá trị

Hour (giờ)

HH

0-23

Minute (phút)

MI

0-59

Second (giây)

SS

0-59

Millisecond (mini giây)

MS

0-999

Day of Year (ngày trong năm)

DY

1-366

Day (ngày trong tháng)

DD

1-31

Week (tuần)

WK

1-53

Weekday (ngày trong tuần)

DW

1-7

Month (tháng)

MM

1-12

Quarter (quý)

QQ

1-4

Year (năm)

YY

1753-9999

Dưới đây là danh sách các hàm ngày tháng mà  SQL Server hỗ trợ :

GETDATE():

Hàm GETDATE() dùng để lấy thời gian hiện tại của hệ thống.

Ví dụ:

SELECT GETDATE() AS [Thời gian hiện tại của hệ thống];

DATEADD():

Hàm DATEADD() dùng để thêm một lượng vào phấn DATEPART của ngày tháng chỉ ra.

Cú pháp:

DATEADD(DATEPART,number,date)

Ví dụ:

SELECT DATEADD(MM,3,'2010-06-20');

Ví dụ trên sẽ thêm vào phần tháng của thời gian hiện tại 3 đơn vị, tức là sẽ hiển thị: 2010-09-20.

DATE_ADD():

Hàm này dùng trong MySQL.

Cú pháp:

DATE_ADD(date, INTERVAL value DATEPART)

Ví dụ:

SELECT DATE_ADD('2018-10-06', INTERVAL 5000 DAY);

Ví dụ trên sẽ thêm 5000 ngày vào thời gian chỉ ra, tức là sẽ hiển thị: 2032-06-14.

DATEDIFF():

Hàm DATEDIFF() dùng để lấy sự chênh lệch theo DATEPART giữa hai giá trị ngày tháng.

Cú pháp:

DATEDIFF(DATEPART,date1,date2)

Ví dụ:

SELECT DATEDIFF(YY,'2000-05-20','2011-10-07');

Ví dụ trên sẽ lấy độ chênh lệch theo năm giữa hai giá trị ngày tháng tương ứng, tức là sẽ hiển thị: 11

Đối với MySQL

Cú pháp:

DATEDIFF(date1,date2) --Quy ra số ngày lệch giữa date1 và date2

Ví dụ:

SELECT DATEDIFF('2015-05-20','2018-10-21') --Sẽ in ra -1250

DATENAME():

Hàm DATENAME() dùng để hiển thị giá trị DATEPART của giá trị ngày tháng tương ứng  dưới dạng chuỗi.

Cú pháp:

DATENAME(DATEPART,date)

Ví dụ:

SELECT DATENAME(MM,'2015-02-03');

Ví dụ trên sẽ hiển thị tháng của giá trị ngày tháng tương ứng dưới dạng chuỗi, tức là sẽ hiển thị: February

DATEPART():

Hàm DATEPART() dùng để lấy một phần thời gian (DATEPART) của giá trị ngày tháng chỉ ra.

Cú pháp:

DATEPART(DATEPART,date)

Ví dụ:

SELECT DATEPART(YY,'2013-05-25');

Ví dụ trên sẽ lấy và hiển thị năm của giá trị ngày tháng tương ứng, tức là sẽ hiển thị: 2013

Hàm toán học (Math)

Các hàm toán học (Math) được dùng để thực hiện các phép toán số học trên các giá trị. Các hàm toán học này áp dụng cho cả SQL SERVER và MySQL. Dưới đây là danh sách các hàm toán học phổ biến.

1. ABS()

Hàm ABS() dùng để lấy giá trị tuyệt đối của một số hoặc biểu thức.

Cú pháp:

ABS(num_expr) -- num là number (số), expr là expression (biểu thức)

Ví dụ 1:

SELECT ABS(-3)

Ví dụ trên sẽ lấy giá trị tuyệt đối của số -3, tức là sẽ hiển thị: 3

Ví dụ 2:

SELECT ABS(3-45)

Ví dụ trên sẽ lấy giá trị tuyệt đối của biểu thức (3-45), tức là sẽ hiển thị: 42

2. CEILING()

Hàm CEILING() dùng để lấy giá trị cận trên của một số hoặc biểu thức, tức là lấy giá trị số nguyên nhỏ nhất nhưng lớn hơn số hoặc biểu thức tương ứng.

Cú pháp:

CEILING(num_expr)

Ví dụ 1:

SELECT CEILING(3.1);

Ví dụ trên sẽ lấy cận trên của số 3.1, tức lá sẽ hiển thị: 4

Ví dụ 2:

SELECT CEILING(3-4.2);

Ví dụ trên sẽ lấy cận trên của biểu thức (3-4.2), tức lá sẽ hiển thị: -1

3. FLOOR()

Ngược với CEILING(), hàm FLOOR() dùng để lấy cận dưới của một số hoặc một biểu thức, tức là lấy giá trị số nguyên lớn nhất nhưng nhỏ hơn số hoặc biểu thức tướng ứng.

Cú pháp:

FLOOR(num_expr)

Ví dụ 1:

SELECT FLOOR(4.9);

Ví dụ trên sẽ lấy cận dưới của số 4.9, tức là sẽ hiển thị: 4

Ví dụ 2:

SELECT FLOOR(6.4-10);

Ví dụ trên sẽ lấy cận dưới của biểu thức (6.4-10), tức là sẽ hiển thị: -4

4. POWER()

POWER() dùng để tính luỹ thừa của một số hoặc biểu thức.

Cú pháp:

POWER(num_expr,luỹ_thừa)

Ví dụ 1:

SELECT POWER(3,2);

Ví dụ trên sẽ tính luỹ thừa 2 của 3 hay là 3 mũ 2, tức là sẽ hiển thị: 9

Ví dụ 2:

SELECT POWER(5-7,3);

Ví dụ trên sẽ tính luỹ thừa 3 của biểu thức (5-7), tức là sẽ hiển thị: -8

5. ROUND()

Hàm ROUND() dùng để làm tròn một số hay biểu thức.

Cú pháp:

ROUND(num_expr,độ_chính_xác)

Ví dụ 1:

SELECT ROUND(1.23456,4);

Ví dụ trên sẽ làm tròn số 1.23456 với độ chính xác 4 con số sau dấu chấm, tức là sẽ hiển thị: 1.2346

6. SIGN()

Hàm SIGN() dùng để lấy dấu của một số hay biểu thức. Hàm trả về +1 nếu số hoặc biểu thức có giá trị dương (>0), -1 nếu số hoặc biểu thức có giá trị âm (<0) và trả về 0 nếu số hoặc biểu thức có giá trị =0.

Cú pháp:

SIGN(num_expr)

Ví dụ 1:

SELECT SIGN(-5);

Ví dụ trên sẽ lấy dấu của số -5, tức là sẽ hiển thị: -1

Ví dụ 2:

SELECT SIGN(2015-2010);

Ví dụ trên sẽ lấy dấu của biểu thức (2015-2010), tức là sẽ hiển thị: 1

7. SQRT()

Hàm SQRT() dùng để tính căn bậc hai của một số hoặc biểu thức, giá trị trả về của hàm là số có kiểu float. Nếu số hay biểu thức có giá trị âm (<0) thì hàm SQRT() sẽ trả về NULL đối với MySQL, trả về lỗi đối với SQL SERVER.

Cú pháp:

SQRT(float_expr)

Ví dụ 1:

SELECT SQRT(9);

Ví dụ trên sẽ tính căn bậc 2 của 9, tức là sẽ hiển thị: 3

Ví dụ 2:

SELECT SQRT(9-5);

Ví dụ trên sẽ tính căn bậc 2 của biểu thức (9-5), tức là sẽ hiển thị: 2

8. SQUARE()

Hàm này dùng để tính bình phương của một số, giá trị trả về có kiểu float. Ví dụ:

SELECT SQUARE(9); --in ra: 81

9. LOG()

Dùng để tính logarit cơ số E của một số, trả về kiểu float. Ví dụ:

SELECT LOG(9) AS N'Logagit cơ số E của 9';

Kết quả:

SQL: Hàm Log(expr)

10. EXP()

Hàm này dùng để tính luỹ thừa cơ số E của một số, giá trị trả về có kiểu float. Ví dụ:

SELECT EXP(LOG(2)) as N'Kết quả của exp(log(2))';

Kết quả:

SQL: Hàm exp()

11. PI()

Hàm này trả về số PI = 3.14159265358979.

12. SIN(), COS(), TAN()

Đây là những hàm dùng để tính sin, cos và tan của một góc theo đơn vị radial, giá trị trả về có kiểu float. Ví dụ:

select SIN(PI()/2) as [SIN(PI()/2)], COS(PI()/2) as [COS(PI()/2)],TAN(PI()/2) as [TAN(PI()/2)];

Kết quả:

SQL: Hàm sin(), cos(), tan()

13. ASIN(), ACOS(), ATAN()

Các hàm này dùng để tính góc (theo đơn vị radial) của một giá trị. Lưu ý là giá trị hợp lệ đối với ASIN() và ACOS() phải nằm trong đoạn [-1,1], nếu không sẽ phát sinh lỗi khi thực thi câu lệnh. Ví dụ:

select ASIN(1) as [ASIN(1)],ACOS(1) as [ACOS(1)],ATAN(1) as [ATAN(1)];

Kết quả:

SQL: Hàm asin(), acos() và atan()

Hàm xếp hạng (Ranking)

Các hàm xếp hạng (Ranking) dùng để xếp hạng các giá trị của một cột nào đó của  tập kết quả có được từ câu lệnh SELECT theo thứ tự tăng dần hoặc giảm dần các giá trị của cột này.

Các hàm xếp hạng bắt buộc phải đi kèm với mệnh đề ORDER BY.

Phạm vi áp dụng: SQL SERVER.

Sau đây là danh sách các hàm xếp hạng:

1. ROW_NUMBER():

Hàm ROW_NUMBER() dùng để xếp hạng tập kết quả một cách tuần tự theo thứ tự bắt đầu từ 1 mà không quan tâm đến các giá trị giống nhau.

Bạn có thể hình dung cách xếp hạng của hàm ROW_NUMBER() ở bảng sau:

ROW_NUMBER() Mark
1 5
2 6
3 6
4 7
5 7
6 8
7 9
8 9
9 10

Cú pháp:

SELECT ROW_NUMBER() OVER(ORDER BY Tên_cột asc/desc) AS Bí_danh, Các_cột FROM Tên_bảng;

Ví dụ:

SELECT ROW_NUMBER() OVER(ORDER BY mark asc) AS [Xếp hạng điểm], mark FROM Marks;

2. DENSE_RANK():

Hàm DENSE_RANK() dùng để xếp hạng các giá trị của một cột theo quy tắc các giá trị giống nhau thuộc cùng một hạng, giá trị nằm sau các giá trị giống nhau sẽ có hạng  lớn hơn 1 đơn vị so với hạng của các giá trị ngay trước nó.

Ví dụ, nếu hạng của các giá trị giống nhau là 5 thì giá trị nằm ngay sau các giá trị giống nhau này sẽ có hạng là: 5 + 1 = 6

Bạn có thể hình dung cách xếp hạng của hàm DENSE_RANK() ở bảng sau:

DENSE_RANK() Mark
1 5
2 6
2 6
3 7
3 7
4 8
5 9
5 9
6 10

Cú pháp:

SELECT DENSE_RANK() OVER(ORDER BY Tên_cột asc/desc) AS Bí_danh, Các_cột FROM Tên_bảng;

Ví dụ:

SELECT DENSE_RANK() OVER(ORDER BY mark asc) AS [Xếp hạng điểm], mark FROM Marks;

3. RANK():

Hàm RANK() dùng để xếp hạng các giá trị của một cột theo quy tắc giống hàm DENSE_RANK(), nhưng khác ở một điểm đó là hạng của giá trị nằm ngay sau các giá trị giống nhau được tính bằng cách lấy hạng của các giá trị giống nhau đó cộng với số lượng các giá trị giống nhau.

Ví dụ, nếu có 2 giá trị giống nhau và hạng của các giá trị giống nhau này là 7 thì hạng của giá trị nằm ngay sau các giá trị giống nhau này sẽ là: 7 + 2 = 9

Bạn có thể hình dung cách xếp hạng của hàm RANK() ở bảng sau:

RANK() Mark
1 5
2 6
2 6
4 7
4 7
6 8
7 9
7 9
9 10

Cú pháp:

SELECT RANK() OVER(ORDER BY Tên_cột asc/desc) AS Bí_danh, Các_cột FROM Tên_bảng;

Ví dụ:

SELECT RANK() OVER(ORDER BY mark asc) AS [Xếp hạng điểm], mark FROM Marks;

Cài đặt SQL Server 2012

Video hướng dẫn cài đặt SQL Server 2012:

Cách thao tác với Database

Video hướng dẫn cách thao tác với DataBase:

Tạo bảng (Create Table)

Video hướng dẫn tạo bảng (Create Table):

SELECT đơn giản

Video hướng dẫn sử dụng câu lệnh SELECT (without FROM):

LEFT, RIGHT & FULL JOIN

1. LEFT JOIN:

LEFT JOIN dùng để lấy dữ liệu liên quan đến hai bảng và lấy thêm những bản ghi nằm ở bảng bên trái kết nối dù những bản ghi này không liên quan đến những bản ghi của bảng nằm bên phải kết nối.

Ví dụ, bảng Student có ba bản ghi lưu trữ ba sinh viên với mã sinh viên là 1, 2 và 3, còn bảng Marks có các bản ghi lưu trữ điểm của các sinh viên có mã 1 và 2. Điều này có nghĩa là sinh viên có mã là 3 không có điểm lưu trữ trong bảng Marks.

Nếu bạn muốn hiển thị tất cả các sinh viên cả có điểm và không có điểm thì ta dùng cú pháp sau:

SELECT Các_cột FROM Bảng_bên_trái Bí_danh1 LEFT JOIN Bảng_bên_phải Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung;

Ví dụ:

SELECT studentname,mark FROM Student a LEFT JOIN Marks b ON a.studentid=b.studentid;

2. RIGHT JOIN:

Ngược với LEFT JOIN, RIGHT JOIN dùng để lấy dữ liệu liên quan đến hai bảng và lấy thêm những bản ghi nằm ở bảng bên phải kết nối dù những bản ghi này không liên quan đến những bản ghi của bảng nằm bên trái kết nối.

Ví dụ, bảng Subjects có ba bản ghi lưu trữ ba môn học với mã tương ứng là là 1, 2 và 3, còn bảng Marks có các bản ghi lưu trữ điểm của các môn học có mã 1 và 2. Điều này có nghĩa là môn học có mã là 3 không có điểm lưu trữ trong bảng Marks.

Nếu bạn muốn hiển thị tất cả các môn học cả có điểm và không có điểm thì ta dùng cú pháp sau:

SELECT Các_cột FROM Bảng_bên_trái Bí_danh1 RIGHT JOIN Bảng_bên_phải Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung;

Ví dụ:

SELECT subjectname,mark FROM Marks a RIGHT JOIN Subjects b ON a.studentid=b.studentid;

3. FULL JOIN:

Đây là sự kết hợp của LEFT JOIN và RIGHT JOIN.

FULL JOIN dùng để lấy dữ liệu liên quan đến các bảng và lấy thêm những bản ghi nằm ở bảng bên trái và bên phải kết nối dù những bản ghi này không liên quan đến những bản ghi của bảng nằm bên trái và bên phải kết nối.

Ví dụ, bảng Student có ba bản ghi lưu trữ ba sinh viên với mã sinh viên là 1, 2 và 3, còn bảng Marks có các bản ghi lưu trữ điểm của các sinh viên có mã 1 và 2. Điều này có nghĩa là sinh viên có mã là 3 không có điểm lưu trữ trong bảng Marks. Còn bảng Subjects có ba bản ghi lưu trữ ba môn học với mã tương ứng là là 1, 2 và 3, còn bảng Marks có các bản ghi lưu trữ điểm của các môn học có mã 1 và 2. Điều này có nghĩa là môn học có mã là 3 không có điểm lưu trữ trong bảng Marks.

Nếu bạn muốn hiển thị tất cả các sinh viên và môn học bao gồm cả điểm và không có điểm thì ta dùng cú pháp sau:

SELECT Các_cột FROM Bảng1 Bí_danh1 FULL JOIN Bảng2 Bí_danh2 ON Bí_danh1.Cột_chung=Bí_danh2.Cột_chung FULL JOIN Bảng3 Bí_danh3 ON Bí_danh2.Cột_chung1=Bí_danh3.Cột_chung1;

Ví dụ:

SELECT * FROM Student a FULL JOIN Marks b ON a.studentid=b.studentid FULL JOIN Subjects c ON b.subjectid=c.subjectid;

Practical 1

1. Tạo một file SQL có tên Lab1.sql

2. Tạo một Cơ sở dữ liệu (CSDL) có tên DBLab1

3. Trong CSDL DBLab1 tạo các bảng và thiết lập các ràng buộc PK, FK theo sơ đồ phía trên.

4. Chèn dữ liệu cho các bảng như dưới đây:

Students

StudentID StudentName Age Email
1 Nguyen Quang An 18 an@yahoo.com
2 Nguyen Cong Vinh 20 vinh@gmail.com
3 Nguyen Van Quyen 19 quyen
4 Pham Thanh Binh 25 binh@com
5 Nguyen Van Tai Em 30 taiem@sport.vn

Classes

ClassID

ClassName

1

C0706L

2

C0708G

ClassStudent

StudentID

ClassID

1

1

2

1

3

2

4

2

5

2

Subjects

SubjectID

SubjectName

1

SQL

2

Java

3

C

4

Visual Basic

Marks

Mark

SubjectID

StudentID

8

1

1

4

2

1

9

1

1

7

1

3

3

1

4

5

2

5

8

3

3

1

3

5

3

2

4

5. Hiển thị danh sách tất cả các học viên.

6. Hiển thị danh sách tất cả các môn học.

7. Tạo ràng buộc Check để kiểm tra độ tuổi nhập vào trong bảng Students phải nằm trong khoảng 15 và 50.

8. Trong bảng Students thêm một cột có tên Status có kiểu bit, sau đó thiết lập ràng buộc default(1) cho cột này.

9. Loại bỏ tất cả các ràng buộc PK và FK giữa các bảng.

Xem thêm

Practical 2

1. Đọc hiểu bài toán quản lý Học viên và Điểm thi sau:

Có một Cơ sở dữ liệu (CSDL) như hình trên.

Bảng Test lưu danh sách các môn học.

Bảng Student lưu danh sách các học viên.

Bảng StudentTest lưu danh sách điểm thi và ngày thi của mỗi học viên với môn thi.

Một học viên chưa thi môn nào nếu như mã học viên (RN) không xuất hiện trong bảng StudentTest. Một môn học chưa có ai thi nếu mã môn học (TestID) không xuất hiện trong bảng StudentTest.

2. Tạo một file có tên Lab2.sql.

3. Tạo một CSDL đặt tên là ‘DBLab2’ và thực hiện các yêu cầu dưới đây.

Tạo 3 bảng và chèn dữ liệu như yêu cầu dưới đây:

Student (Lưu danh sách các học viên gồm mã học viên(RN), tên(Name), tuổi(Age)).

RN (int primary key)

Name (VarChar (20))

Age (tinyint)

1

Nguyen Hong Ha

20

2

Truong Ngoc Anh

30

3

Tuan Minh

25

4

Dan Truong

22

Test (Lưu danh sách môn học gồm mã môn học (TestID, tên môn học(Name)).

TestID (int primary key)

Name (Varchar(20))

1

EPC

2

DWMX

3

SQL1

4

SQL2

StudentTest (Lưu điểm thi của học viên với từng môn thi, gồm mã học viên (RN), mã môn học (TestID), ngày thi(Date), điểm thi(Mark)).

RN (int foreign key tham chiếu tới RN của Student)

TestID (int foreign key tham chiếu tới TestID của Test)

Date (Date)

Mark (Float)

1

1

7/17/2006

8

1

2

7/18/2006

5

1

3

7/19/2006

7

2

1

7/17/2006

7

2

2

7/18/2006

4

2

3

7/19/2006

2

3

1

7/17/2006

10

3

3

7/18/2006

1

a. Đưa ra điểm của học viên dưới dạng 4 chữ số, 2 chữ số sau dấu phảy.

b. Hiển thị những học viên có tuổi >25.

c. Hiển thị những học viên có tuổi là 20 hoặc 30.

d. Hiển thị những môn học có chứa ký tự ‘s’.

e. Hiển thị tất cả những bản ghi có điểm số >5 trong bảng StudentTest.

f. Hiển thị những học viên có tên gồm 4 ký tự.

g. Hiển thị những học viên có họ gồm 6 ký tự.

h. Hiển thị những học viên có họ gồm 6 ký tự nhưng không chứa ký tự ‘r’.

i. Thêm trường (cột) tên là Status có kiểu varchar(10) và giá trị mặc định là ‘Young’ vào bảng Student (tham khảo bài viết: Thao tác với cột (Column)).

k. Xóa các ràng buộc khóa ngoại.

l. Xóa các ràng buộc khóa chính.

m. Xóa các bảng.

n. Xóa CSDL.

Extra:

1. Đưa ra tuổi trung bình của các học viên.

2. Tìm những học viên có tuổi cao nhất.

3. Tìm những học viên có tuổi thấp nhất.

4. Tìm những môn học có điểm cao nhất.

5. Tìm những môn học có điểm thấp nhất.

6. Tìm những học viên đã thi gần đây nhất.

7. Tìm những học viên đã thi đầu tiên.

8. Tính tổng tuổi của các học viên.

9. Tính xem đến thời điểm này mỗi môn học đã thi được bao nhiêu ngày rồi.

10. Tìm những học viên đạt điểm cao nhất.

11. Tìm những học viên có điểm thấp nhất.

12. Tính điểm trung bình cho mỗi học viên, điểm phải được sắp xếp giảm dần và được hiển thị dưới dạng 4 số, 2 chữ số sau dấu phảy.

13. Hiển thị danh sách các học viên đã tham gia thi, các môn thi được thi bởi các học viên đó.

14. Hiển thị danh sách các bạn học viên chưa thi môn nào.

15. Hiển thị danh sách học viên phải thi lại, tên môn học phải thi lại và điểm thi (điểm phải thi lại là điểm nhỏ hơn 5).

16. Hiển thị tên và điểm trung bình của học viên có điểm trung bình lớn nhất.

17. Hiển thị tên và điểm trung bình của học viên có điểm trung bình nhỏ nhất.

18. Hiển thị điểm thi cao nhất của từng môn học.

19. Hiển thị danh sách tất cả các học viên và môn học mà các học viên đó đã thi, nếu học viên chưa thi môn nào thì phần tên môn học để Null (gợi ý: ý này có liên quan đến phần LEFT, RIGHT & FULL JOIN).

VIDEO SOLUTION

Xem hướng dẫn giải tại: https://youtu.be/san5ua2K1Ro

Xem thêm

Practical 3

1. Tạo một file có tên Lab3.sql.

2. Tạo một cơ sở dữ liệu đặt tên là DBLab3.

3. Tạo 4 bảng sau đó chèn dữ liệu vào theo các bước sau:

- Bước 1: Tạo 4 bảng.

- Bước 2: Áp đặt các ràng buộc (constraint) khóa chính và khóa ngoại lên các bảng như mô tả dưới đây (chú ý: sử dụng câu lệnh alter table để đặt các ràng buộc).

- Bước 3: Chèn dữ liệu vào các bảng.

Customer (Lưu mã(cID), tên(cName), tuổi(cAge) và giới tính(cGender) của khách hàng).

cID (int primary key)

cName (VarChar (25))

cAge (tinyint)

cGender (bit)

1

Elisha Cuthbert

26

0

2

Cristiano Ronaldo

23

1

3

Gemma Atkinson

24

0

4

Maria Sharapova

22

Null

Orders (Lưu mã hóa đơn(oID), mã khách hàng(cID) và ngày khởi tạo hóa đơn(oDate)).

oID (int primary key)

cID (int)

(foreign key tham chiếu tới cID của Customer)

oDate (Date)

1

1

3/21/2008

2

2

3/23/2008

3

1

3/16/2008

Product (Lưu mã(pID), tên(pName) và giá của các sản phẩm(pPrice)).

pID (int primary key)

pName (varchar(25))

pPrice (int)

1

Washing Machine

3

2

Fridge

5

3

Air Conditioner

7

4

Electric Fan

1

5

Electric Cooker

2

OrderDetail (Lưu mã hóa đơn(oID), mã sản phẩm(pID) và số lượng sản phẩm(odQTY) trong hóa đơn).

oID (int)

(foreign key tham chiếu tới oID của Order)

pID (int)

(foreign key tham chiếu tới pID của Product)

odQTY (int)

 

1

1

3

1

3

7

1

4

2

2

1

1

3

1

8

2

5

4

2

3

3

 

4. Hiển thị danh sách các hóa đơn (chú ý: danh sách phải được sắp xếp theo trường oDate).

5. Hiển thị danh sách khách hàng gồm tên và ký tự đầu tiên của tên.

6. Hiển thị những sản phẩm có giá cao nhất.

7. Hiển thị những sản phẩm có giá thấp nhất.

8. Hiển thị danh sách sản phẩm gồm tên và giá kết hợp trong 1 cột như sau:

‘Price of ’ + pName + ‘ is ’ + pPrice.

9. Tạo một bảng đặt tên là ‘Top3Product’ , bảng này chứa 3 sản phẩm có giá cao nhất gồm tên và giá của sản phẩm.

Gợi ý: Bạn nên dùng câu lệnh SELECT với INTO để tạo bảng mới.

10. Hiển thị những khách hàng mà tên có độ dài 15 ký tư.

11. Hiển thị tất cả các sản phẩm có chuỗi ‘Electric’ ở trong pName.

12. Hiển thị ngày giờ hiện tại và ngày giờ hiện tại cộng thêm 5000 phút.

13. Xóa tất cả các khóa ngoại.

14. Xóa tất cả các khóa chính.

Practical 4

1. Tạo một file SQL có tên Lab4.sql.

2. Tạo một Cơ sở dữ liệu (CSDL) có tên DBLab4.

3. Tạo 03 bảng như sau:

- Bảng Customers lưu trữ thông tin về khách hàng gồm các cột MaKhach (PK), Ten, SoDienThoai.

- Bảng Items lưu trữ thông tin về hàng hóa gồm các cột MaHang (PK), Ten, SoLuong, DonGia.

- Bảng CustomerItem lưu trữ thông tin về những sản phẩm đã được bán mua gồm các cột MaKhach, MaHang, SoLuongMua, trong đó PK nằm trên 2 cột MaKhach và MaHang, FK1 nằm trên cột MaKhach, FK2 nằm trên cột MaHang.

4. Nhập các thông tin sau vào bảng Items:

Tên sản phẩm

Số lượng

Đơn giá (nghìn đồng)

Tu lanh

5

3500

Ti vi

2

3000

Dieu hoa

1

8000

Quat da

5

1700

May giat

3

5000

5. Tách lọc và nhập thông tin sau vào hai bảng Customers và CustomerItem:

Tên khách hàng

Số điện thoại

Hàng đã mua

Số lượng mua

Dinh Truong Son

1234567

Tu lanh

4

Dinh Truong Son

1234567

May giat

1

Mai Thanh Minh

1357999

Ti vi

1

Nguyen Hong Ha

2468888

Dieu hoa

1

Nguyen Hong Ha

2468888

Tu lanh

1

 

6. Hiển thị tổng số tiền mà cửa hàng đã thu được từ các khách hàng trên.

7. Hiển thị tên, số tiền đã mua của người khách hàng đã trả tiền cho cửa hàng nhiều nhất.

8. Kiểm tra xem người khách có số điên thoại 2468888 có mua mặt hàng Tủ lạnh không, nếu có mua thì hiện ra dòng chữ 'Có mua', ngược lại hiện ra dòng chữ 'Không mua'.

9. Tính tổng số hàng hóa và tổng tiền còn lại trong kho (số còn lại bằng tổng số trừ đi số đã bán).

10. Hiển thị danh sách 3 mặt hàng bán chạy nhất(số lượng bán nhiều nhất).

11. Hiển thị tất cả các mặt hàng mà chưa bán được một sản phẩm nào.

12. Hiển thị danh sách những người mua nhiều hơn một mặt hàng.

13. Hiển thị danh sách những người mua hàng có số lượng nhiều hơn một cái.

14. Hiển thị tên khách hàng, tổng số tiền mua hàng của từng khách và hiển thị cột Level với giá trị điền vào cột này theo tiêu chí sau: Nếu tổng số tiền mua hàng của từng khách < 5000 thì điền giá trị là 'Level1', từ 5000 đến < 10000 thì điền giá trị là 'Level2', >=10000 thì điền giá trị là 'V.I.P'.

Xem thêm

Practical 5

1. Tạo một file có tên Lab5.sql.

2. Tạo một CSDL có tên DBLab5.

3. Tạo ba bảng như sau (Sinh viên tự áp dụng kiểu dữ liệu cho mỗi cột cho hợp lý):

- Bảng Student(RN,Name,Age,Gender).

- Bảng Subject(sID, sName).

- Bảng StudentSubject(RN,sID,Mark,Date).

4. Đặt khóa chính (PK) cho các bảng:

- Bảng Student PK nằm trên cột RN.

- Bảng Subject PK nằm trên cột sID.

- Bảng StudentSubject PK nằm trên hai cột (RN,sID).

5. Đặt ràng buộc để trường Mark chỉ nhận các giá trị trong đoạn [0,10].

6. Đặt ràng buộc khóa ngoại giữa 2 bảng Student(RN) và StudentSubject(RN).

7. Đặt ràng buộc khóa ngoại giữa 2 bảng Subject(sID) và StudentSubject(sID).

8. Nhập dữ liệu vào bảng để thể hiện thông tin sau:

- Học viên Mỹ Linh đạt điểm 8 môn SQL vào ngày 7/28/2005.

- Học viên Đàm Vĩnh Hưng đạt điểm 3 môn LGC vào ngày 7/29/2005.

- Học viên Kim Tử Long đạt điểm 9 môn HTML vào ngày 7/31/2005.

- Học viên Tài Linh đạt điểm 5 môn SQL vào ngày 7/30/2005.

- Học viên Mỹ Lệ đạt điểm 10 môn CF vào ngày 7/19/2005.

- Học viên Ngọc Oanh đạt điểm 9 môn SQL vào ngày 7/25/2005.

9. Cập nhật giới tính cho các học viên:

- Mỹ Linh, Tài Linh, Mỹ Lệ là 0.

- Kim Tử Long là 1.

10. Nhập thêm các môn học sau vào bảng Subject: Core Java và VB.Net.

11. Hiển thị tất cả các môn học mà chưa có học viên nào nhận điểm.

12. Hiển thị danh sách tất cả các môn học, với điểm cao nhất mà học viên đạt được với môn học đó, môn nào chưa có điểm thì để trống (Null) phần điểm.

13. Hiển thị tên môn học mà có nhiều hơn một điểm.

14. Hiển thị những thông tin sau về học viên: RN, sID, Name, Age, Gender, sName, Mark, Date. Lưu ý là đối với trường Gender hiển thị Male thay cho 1, Female thay cho 0 và Unknow thay cho Null.

15. Tạo các Index trên các cột sau: Cột Name của bảng Student, cột sName của bảng Subjects, cột (RN,sID) của bảng StudentSubject.

16. Tạo một bảng tên là Top3 với các cột (RN, Name, Mark, sName, Date) với dữ liệu gồm chỉ 3 dòng có điểm cao nhất, cột Rank sẽ chứa số thứ tự từ 1 đến 3(dòng đầu tiên là 1, dòng thứ 2 là 2 và dòng thứ 3 là 3), còn cột Date sẽ nhận giá trị là ngày cập nhật thông tin.

17. Hiển thị danh sách toàn bộ các học sinh giỏi (Học sinh giỏi là những người có điểm trung bình lớn hơn 8.0 và không có điểm nào dưới 5).

18. Hiển thị danh sách toàn bộ các học sinh khá (Học sinh khá là những người có điểm trung bình lớn hơn 6.5 và chỉ có tối đa 1 điểm dưới 5, và điểm này không được dưới 3).

Xem thêm

Practical 6

1. Tạo một file có tên: họ_và_tên_Lab6.sql (ví dụ: DangTranLong_Lab6.sql).

2. Tạo một Cơ sở dữ liệu có tên họ_và_tên_Lab6 (ví dụ: DangTranLong_Lab6).

3. Tạo ba bảng và chèn dữ liệu như sau:

Students (chứa danh sách Sinh viên).

StudentID (int)

Name (VarChar(50))

Age (tinyint)

stGender (bit)

1

Joe Hart

25

1

2

Colin Doyle

20

1

3

Paul Robinson

16

Null

4

Luis Garcia Paulson

17

0

5

Ben Foster

30

1

Projects (chứa danh sách dự án).

PID(int)

PName (Varchar (50))

Cost (float)

Type (Varchar(10))

1

NewYork Bridge

100

Null

2

Tenda Road

60

Null

3

Google Road

200

Null

4

The Star Bridge

50

Null

StudentProject (chứa danh sách Sinh viên làm việc cho các Dự án). Ví dụ: hàng đầu tiên của bảng dưới đây thể hiện rằng ‘Joe Hart’ (có mã 1 ở bảng Students) làm việc cho dự án ‘The Star Bridge’ (có mã là 4 ở bảng Projects) từ ngày ‘15/05/09’ và làm việc trong 3 tháng.

StudentID (int)

PID (int)

WorkDate (date)

Duration (int)

1

4

15/05/09

3

2

2

14/05/09

5

2

3

20/05/09

6

2

1

16/05/09

4

3

1

16/05/09

6

3

4

19/05/09

7

4

4

21/05/09

8

 

4. Các ràng buộc cần tạo:

a. Ràng buộc Check trên cột Age của bảng Students để kiểm tra độ tuổi nhập vào phải nằm trong khoảng (Age > 15 và Age < 33).

b. Ràng buộc khóa chính trên các cột: StudentID của bảng Students, PID của bảng Projects, (StudentID,PID) của bảng StudentProject.

c. Ràng buộc Default trên cột Duration của bảng StudentProject với giá trị mặc định là 0.

d. Ràng buộc khóa ngoại trên các cột: StudentID của bảng StudentProject tham chiếu đến bảng Students, PID của bảng StudentProject tham chiếu đến bảng Projects.

5. Cập nhật giá trị trên cột Type của bảng Projects như sau:

- Type=’Education’ nếu Cost < 80.

- Type=’Normal’ nếu Cost >= 80 và Cost <= 150.

- Type=’Government’ nếu Cost > 150.

6. Hiển thị những Sinh viên làm việc cho hơn một Dự án.

7. Hiển thị những Sinh viên có tổng số thời gian làm việc cho các dự án là lớn nhất (gợi ý: dựa vào cột Duration).

8. Hiển thị những Sinh viên có tên chứa cụm từ ‘Paul’ làm việc cho Dự án ‘The Star Bridge’.

9. Hiển thị những Sinh viên không làm việc cho dự án nào.

10. Tạo View có tên ‘vwStudentProject’ để hiển thị thông tin như sau (lưu ý phải sắp xếp dữ liệu tăng dần theo tên sinh viên): Tên sinh viên, tên dự án, workdate và duration.

11.Tạo Index có tên ‘ixStudentName’ trên hai cột [Student Name]  và [Project Name] của View ‘vwStudentProject’.

12. Tạo thủ tục lưu trữ có tên ‘spWorkin’ có một tham số, tham số này nhận vào tên của Sinh viên.

- Nếu tên này có trong bảng Students thì hiển thị thông tin về Sinh viên tương ứng và những Dự án mà Sinh viên đó đã làm việc.

- Nếu tham số nhận vào chuỗi ‘any’ thì hiển thị tên của tất cả các Sinh viên cùng những Dự án mà họ đã làm.

13. Tạo Trigger có tên ‘tgUpdateTrig’ trên bảng Students, trigger này có nhiệm vụ như sau: nếu sửa giá trị trên cột StudentID của bảng Students thì giá trị tương ứng trên cột StudentID của bảng StudentProject củng phải được sửa theo.

14. Tạo thủ tục lưu trữ có tên ‘spDropOut’ có một tham số, tham số này nhận vào tên của Dự án. Nếu tên này có trong bảng Projects thì sẽ xóa tất cả thông tin liên quan đến dự án đó trong tất cả các bảng liên quan của Cơ sở dữ liệu.

Xem thêm

Practical 7

1. Tạo một file có tên dạng: Họ_và_tên_Lab7.sql, ví dụ: DangTranLongLab7.sql.

2. Tạo một Cơ sở dữ liệu tên trùng với tên file, ví dụ: DangTranLongLab7.

3. Tạo ba bảng và chèn dữ liệu như sau:

Customer (lưu trữ Khách hàng)

CustomerID

(int)

Name

(varchar (30))

Birth

(date)

Gender

(bit)

1

Jonny Owen

10/10/1980

1

2

Christina Tiny

10/03/1989

0

3

Garry Kelley

16/03/1990

Null

4

Tammy Beckham

17/05/1980

0

5

David Phantom

30/12/1987

1

 Product (Lưu trữ Sản phẩm)

ProductID

(int)

Name

(varchar (30))

Pdesc

(text)

Pimage

(varchar(200))

PStatus

(bit)

1

Nokia N90

Mobile Nokia

image1.jpg

1

2

HP DV6000

Laptop

image2.jpg

NULL

3

HP DV2000

Laptop

image3.jpg

1

4

SamSung G488

Mobile SamSung

image4.jpg

0

5

LCD Plasma

TV LCD

image5.jpg

0

Comment (lưu trữ bình luận của Khách đối với Sản phẩm). Ví dụ: bản ghi đầu tiên của bảng dưới thể hiện rằng ‘Jonny Owen’ (mã là 1 ở bảng Customer) đã bình luận cho sản phẩm ‘Nokia N90’ (mã là 1 ở bảng Product)   vào ngày ‘15/03/09’).

ComID(int

identity(1,1))

ProductID

(int)

CustomerID

(int)

Date

(datetime)

Title

(varchar(200)

Content

(text)

Status

(bit)

1

1

1

15/03/09

Hot product

null

1

2

2

2

14/03/09

Hot price

Very much

0

3

3

2

20/03/09

Cheapest

Unlimited

0

4

4

2

16/04/09

Sale off

50%

1


- Ràng buộc Default cho cột Date của bảng Comment với giá trị mặc định là ngày hiện tại.
Các ràng buộc phải tạo:

- Ràng buộc khóa chính trên cột: CustomerID của bảng Customer, ProductID của bảng Product và ComID của bảng Comment.

- Ràng buộc khóa ngoại trên cột: ProductID của bảng Comment tham chiếu đến bảng Product và CustomerID cũng của bảng Comment tham chiếu đến bảng Customer.

- Ràng buộc Unique cho cột Pimage trên bảng Product.

4. Hiển thị những sản phẩm có PStatus là null hoặc 0.

5. Hiển thị những sản phẩm không có bình luận nào.

6. Hiển thị những Khách có nhiều bình luận nhất.

7. Tạo View có tên ‘vwFull_Information’ để xem tất cả các bình luận gồm các cột sau:

Mã bình luận, tên Khách, tên Sản phẩm, ngày bình luận, tiêu đề bình luận, nội dung bình luận và trạng thái bình luận, trong đó trạng thái bình luận hiển thị là ‘Accept’ thay cho 1 và ‘Not Accept’ thay cho 0.

8. Tạo View có tên ‘vwCustomerList’ để liệt kê thông tin của tất cả các Khách hàng gồm tất cả các cột của bảng Customer và cột Status, trong đó cột Gender hiển thị là ‘Male’ thay cho 1, ‘Female’ thay cho 0 và ‘Unknow’ thay cho Null, cột Status hiển thị là ‘Old’ nếu tuổi của khách>=30 và ‘Young’ nếu tuổi của khách<30.

9. Sửa View ‘vwCustomerList’ để nó chỉ chứa các cột CustomerID, Customer Name, Birth, Gender của bảng Customer và tạo chỉ mục (index) có tên ixCustomerName trên cột [Customer Name] của view này.

10. Tạo thủ tục lưu trữ có tên ‘spStudent’ có một tham số tên @Name.

- Nếu tìm thấy @Name trong cột Name của bảng Product thì sẽ liệt kê tất cả những bình luận cho những Sản phẩm có tên tương tự (like) @Name.

- Nếu không thì kiểm tra @Name nếu tìm thấy trong Name của bảng Customer thì sẽ liệt kệ tất cả những bình luận của những Khách có tên tương tự (like) @Name

- Còn nếu @Name nhận giá trị ‘*’ thì sẽ liệt kê tất cả các bình luận đang có.

11. Tạo Trigger có tên ‘tgUpdateProduct’ trên bảng Product để khi cập nhật giá trị trên cột ProductID của bảng Product thì trigger sẽ tự cập nhật giá trị tương ứng lên trên cột ProductID của bảng Comment.

12. Tạo thủ tục lưu trữ có tên ‘spDropOut’ có một  tham số là tên của Khách hàng, nếu tìm thấy tên này trong cột Name của bảng Customer thì sẽ xóa tất cả những thông tin của tất cả những Khách hàng có tên tương ứng đó trên tất cả các bảng liên quan của Cơ sở dữ liệu.

Xem thêm

SELECT với INTO

Câu lệnh SELECT với INTO dùng để tạo một bảng mới có tên là Tên_bảng_mới, trong đó các cột của bảng mới chính là Các_cột, còn các hàng dữ liệu của bảng mới chính là tập kết quả có được qua câu lệnh SELECT.

Cú pháp:

SELECT Các_cột INTO Tên_bảng_mới FROM Các_bảng_liên_kết [where Điều_kiện];

Ví dụ:

SELECT a.studentid, studentname, subjectname, mark INTO Student8 from Student a JOIN Marks b ON a.studentid=b.studentid JOIN Subjects c ON b.subjectid=c.subjectid WHERE mark>=8;

Câu lệnh trên sẽ tạo ra một bảng mới có tên Student8, bảng này có các cột là studentid, studentname, subjectname và mark; các hàng của bảng Student8 chính là tập kết quả của câu lệnh SELECT.

SELECT với WHERE

Câu lệnh SELECT với WHERE được dùng để thiết lập truy vấn có điều kiện. Loại câu lệnh này được xem là phổ biến và phức tạp nhất trong các truy vấn SQL. Cú pháp cơ bản của câu lệnh này được thể hiện như sau:

SELECT Các_cột FROM Các_bảng_liên_kết WHERE Điều_kiện;

, trong đó, để thiết lập Điều_kiện được dễ dàng hơn SQL đưa ra một số quy cách sau đây:

Các phép toán so sánh

= : So sánh bằng

<> hoặc != : So sánh khác

> : So sánh lớn hơn

>= : So sánh lớn hơn hoặc bằng

< : So sánh nhỏ hơn

<= : So sánh nhỏ hơn hoặc bằng

Ví dụ:

Tìm những sinh viên có họ và tên là 'Nguyễn Văn A' :

SELECT * FROM Student WHERE studentname = N'Nguyễn Văn A';

Tìm những sinh viên có họ và tên không phải là 'Nguyễn Văn A' :

SELECT * FROM Student WHERE studentname <> N'Nguyễn Văn A';

NOT

NOT được dùng trong trường hợp bạn muốn tìm những dữ liệu ngược với điều kiện. Cú pháp:

SELECT Các_cột FROM Các_bảng_liên_kết WHERE NOT Điều_kiện;

Ví dụ, nếu bạn muốn tìm những bạn sinh viên có mã  từ 4 trở xuống thì bạn có thể làm như sau:

SELECT * FROM Student WHERE NOT studentid>=5;

Còn đây là ví dụ tìm những sinh viên có họ và tên không phải là 'Nguyễn Văn A':

SELECT * FROM Student WHERE NOT studentname = N'Nguyễn Văn A';

LIKE và NOT LIKE

LIKE được dùng trong trường hợp bạn muốn tìm dữ liệu tương tự hay gần giống với yêu cầu đề ra. Chẳng hạn nếu bạn muốn tìm những Sinh viên có tên là 'Anh' thì bạn sẽ cần dùng đến LIKE.

SQL đưa ra một số ký tự dạng đặc biệt sau đây khi áp dụng LIKE:

% : tương đương với một chuỗi bất kỳ.

_ : (dấu gạch dưới) tương đương với một ký tự bất kỳ.

[] : tương đương với một ký tự bất kỳ nằm trong cặp []. Ví dụ, [abc] tương đương với a hoặc b hoặc c.

[^] : tương đương với một ký tự bất kỳ không nằm trong cặp []. Ví dụ, [^abc] tương đương với một ký tự bất kỳ mà không phải a hay b hay c.

Ví dụ dưới đây sẽ tìm những sinh viên có họ là 'Hoàng':

SELECT * FROM Student WHERE studentname LIKE N'Hoàng %';

Tìm những sinh viên có tên là 'Anh':

SELECT * FROM Student WHERE studentname LIKE N'% Anh';

Tìm những sinh viên có tên gồm 3 ký tự:

SELECT * FROM Student WHERE studentname LIKE N'% ___'; -- 3 dấu gạch dưới

Tìm những sinh viên có tên có ký tự cuối là 'A' hoặc 'C':

SELECT * FROM Student WHERE studentname LIKE N'%[AC]';

Tìm những sinh viên có tên có ký tự cuối không phải là 'A' hoặc 'C':

SELECT * FROM Student WHERE studentname LIKE N'%[^AC]';

NOT LIKE lại có tác dụng ngược với LIKE, tức là nó được dùng trong trường hợp bạn không muốn tìm dữ liệu tương tự hay gần giống với yêu cầu đề ra. Chẳng hạn nếu bạn không muốn tìm những Sinh viên có tên là 'Anh' thì bạn sẽ dùng NOT LIKE.

Tìm những Sinh viên có họ không phải là 'Hoàng':

SELECT * FROM Student WHERE studentname NOT LIKE N'Hoàng %';

Tìm những Sinh viên có tên không phải là 'Anh':

SELECT * FROM Student WHERE studentname NOT LIKE N'% Anh';

BETWEEN và NOT BETWEEN:

BETWEEN được dùng trong trường hợp bạn muốn truy xuất những dữ liệu với điều kiện dữ liệu nằm trong một đoạn (range) nào đó.

Cú pháp của BETWEEN:

BETWEEN Giá_trị1 AND Giá_trị2

Ví dụ cho BETWEEN:

Nếu bạn muốn lấy những Sinh viên có mã từ 2 đến 9 bạn làm như sau:

SELECT * FROM Student WHERE studentid BETWEEN 2 AND 9;

NOT BETWEEN có tác dụng ngược với BETWEEN, nghĩa là sẽ lấy dữ liệu với điều kiện dữ liệu không nằm trong đoạn nào đó.

Cú pháp NOT BETWEEN:

NOT BETWEEN Giá_trị1 AND Giá_trị2

Ví dụ NOT BETWEEN:

Nếu bạn muốn lấy những Sinh viên có mã không nằm trong đoạn từ 2 đến 9 bạn làm như sau:

SELECT * FROM Student WHERE studentid NOT BETWEEN 2 AND 9;

IN() và NOT IN():

IN() được dùng trong trường hợp bạn muốn truy xuất những dữ liệu với điều kiện dữ liệu bao gồm các giá trị cụ thể nào đó.

Cú pháp IN():

IN(Giá_trị1, Giá_trị2, Giá_trị3, ...)

Ví dụ IN():

Nếu bạn muốn xem thông tin của những Sinh viên có mã 3, 5, 7 và 9 bạn làm như sau:

SELECT * FROM Student WHERE studentid IN(3, 5, 7, 9);

NOT IN() được dùng trong trường hợp bạn muốn truy xuất những dữ liệu với điều kiện dữ liệu không bao gồm các giá trị cụ thể nào đó.

Cú pháp NOT IN():

NOT IN(Giá_trị1, Giá_trị2, Giá_trị3, ...)

Ví dụ NOT IN():

Nếu bạn muốn xem thông tin của những Sinh viên có mã không phải là 3, 5, 7 hay 9 bạn làm như sau:

SELECT * FROM Student WHERE studentid NOT IN(3, 5, 7, 9);

GROUP BY

Mệnh đề GROUP BY dùng để phân nhóm tập kết quả thành một hoặc nhiều nhóm con. Mỗi nhóm con có giá trị và biểu thức chung.

GROUP BY là bắt buộc nếu có hàm tập hợp (aggregate) và một hoặc nhiều cột tham gia vào trong câu lệnh SELECT, và GROUP BY sẽ sinh ra một giá trị duy nhất cho mỗi tập hợp.

Cú pháp:

SELECT Các_cột, Hàm_tập_hợp FROM Các_bảng_liên_kết [WHERE Điều_kiện] GROUP BY  Các_cột,[Các_cột1] [ORDER BY ...];

Lưu ý rằng ở sau SELECT có Các_cột thì sau GROUP BY cũng phải có Các_cột, nghĩa là sau SELECT có những cột nào thì sau GROUP BY bắt buộc cũng phải có những cột đó.

Trong trường hợp cần thiết bạn có quyền đưa thêm Các_cột1 vào để việc phân nhóm cho tập kết quả được chính xác.

Ví dụ:

Tính tổng điểm của từng sinh viên:

SELECT studentname, SUM(mark) as N'Tổng điểm] FROM Student a JOIN Marks b on a.studentid=b.studentid GROUP BY  studentname,a.studentid ORDER BY SUM(mark) DESC;

Ở ví dụ trên, nếu không đưa thêm cột a.studentid vào thì kết quả có thể sẽ bị sai, bởi vì việc phân nhóm là theo cột studentname, tức là những sinh viên có họ và tên giống nhau sẽ được phân thành một nhóm, mà họ tên của những sinh viên khác nhau thì có thể trùng nhau, nên cần phải đưa thêm mã sinh viên vào việc phân nhóm để đảm bảo những sinh viên có cùng họ tên không bị xếp thành một nhóm.

Tính điểm trung bình cho từng sinh viên:

SELECT studentname, AVG(mark) as N'Trung bình cộng] FROM Student a JOIN Marks b on a.studentid=b.studentid GROUP BY  studentname,a.studentid;

ORDER BY

Mệnh đề ORDER BY dùng để sắp xếp theo thứ tự tăng hoặc giảm các giá trị của một cột hoặc một tập cột.

Cú pháp:

ORDER BY Cột1 [ASC/DESC], Cột2 [ASC/DESC], Cột2 [ASC/DESC], ...

, trong đó ASC (Ascending) tức là tăng dần (đây là hướng sắp xếp mặc định, tức là nếu không có ASC hay DESC sau Cột thì mặc định sắp xếp là ASC-tăng dần), DESC (Descending) tức là giảm dần.

Sự ưu tiên sắp xếp dữ liệu tuân theo thứ tự cột bên trái trước, bên phải sau, nghĩa là dữ liệu của Cột1 được sắp xếp trước, nếu có giá trị trùng nhau thì sẽ chuyển sang sắp xếp dữ liệu ở Cột2, ...

Lưu ý rằng ORDER BY phải nằm sau mệnh đề GROUP BY.

Ví dụ:

Hiển thị danh sách Sinh viên trong đó cột studentname sắp xếp theo thứ tự tăng dần:

Select * from Student ORDER BY studentname;

Nếu bạn muốn xem danh sách Sinh viên với điểm số tương ứng tăng dần bạn làm như sau:

SELECT studentname,subjectname,mark FROM Student a JOIN Marks b on a.studentid=b.studentid JOIN Subjects c on b.subjectid=c.subjectid ORDER BY mark ASC; 

Nếu bạn muốn xem danh sách Sinh viên với điểm số tương ứng giảm dần, và nếu có các giá trị điểm số trùng nhau của các Sinh viên thì sắp xếp tên Sinh viên theo thứ tự tăng dần bạn làm như sau:

SELECT studentname,subjectname,mark FROM Student a JOIN Marks b on a.studentid=b.studentid JOIN Subjects c on b.subjectid=c.subjectid ORDER BY mark DESC, studentname ASC;

CASE-WHEN

Tổng quan

CASE-WHEN dùng để thiết lập điều kiện rẽ nhánh trong SQL. CASE-WHEN có thể áp dụng được cho  các câu lệnh DML gồm SELECTUPDATE.

Dưới đây sẽ hướng dẫn cách sử dụng CASE-WHEN cho câu lệnh SELECT, bạn có thể xem cách sử dụng CASE-WHEN cho câu lệnh UPDATE tại bài viết về UPDATE.

Khi sử dụng cho SELECT thì CASE-WHEN sẽ thể hiện ở một cột riêng và ta có thể đặt bí danh cho cột này.

Cú pháp

Có hai cú pháp sử dụng CASE-WHEN được thể hiện cụ thể như sau:

Cú pháp 1

SELECT Các_cột, Bí_danh = CASE Tên_cột

WHEN Giá_trị1 then Hiển_thị1

WHEN Giá_trị2 then Hiển_thị2

...

ELSE Hiển_thị

END

FROM Các_bảng_liên_kết [WHERE Điều_kiện];

Hoặc:

SELECT Các_cột, CASE Tên_cột

WHEN Giá_trị1 then Hiển_thị1

WHEN Giá_trị2 then Hiển_thị2

...

ELSE Hiển_thị

END AS Bí_danh

FROM Các_bảng_liên_kết [WHERE Điều_kiện];

Ví dụ:

Giả sử bảng Student có các dữ liệu sau đây:

studentid studentname gender
1 A 1
2 B 0
3 C Null
4 A 0

Bây giờ ta muốn hiển thị toàn bộ dữ liệu của bảng Student trong đó cột gender sẽ hiển thị 'Male' thay cho 1, 'Female' thay cho 0 và 'Unknow' thay cho Null. Ta làm như sau:

SELECT studentid, studentname, GENDER = CASE gender

WHEN 1 then 'Male'

WHEN 0 then 'Female'

ELSE 'Unknow'

END

FROM Student;

Hoặc:

SELECT studentid, studentname, CASE gender

WHEN 1 then 'Male'

WHEN 0 then 'Female'

ELSE 'Unknow'

END AS GENDER

FROM Student;

 

Kết quả sẽ hiển thị như sau:

studentid studentname GENDER
1 A Male
2 B Female
3 C Unknow
4 A Female

Cú pháp 2

SELECT Các_cột, Bí_danh = CASE

WHEN Điều_kiện1 then Hiển_thị1

WHEN Điều_kiện2 then Hiển_thị2

...

ELSE Hiển_thị

END

FROM Các_bảng_liên_kết [WHERE Điều_kiện];

Hoặc:

SELECT Các_cột, CASE

WHEN Điều_kiện1 then Hiển_thị1

WHEN Điều_kiện2 then Hiển_thị2

...

ELSE Hiển_thị

END AS Bí_danh

FROM Các_bảng_liên_kết [WHERE Điều_kiện];

Ví dụ:

Hiển thị tên khách hàng, tổng số tiền mua hàng của từng khách và hiển thị cột Level với giá trị điền vào cột này theo tiêu chí sau: Nếu tổng số tiền mua hàng của từng khách < 5000 thì điền giá trị là 'Level1', từ 5000 đến < 10000 thì điền giá trị là 'Level2', >=10000 thì điền giá trị là 'V.I.P' (Câu 14 bài tập Practical 4). Ta giải quyết yêu cầu này như sau:

SELECT c.Ten, SUM(b.SoLuongMua * a.DonGia) AS [TongTienMua], [Level] = CASE

  WHEN SUM(b.SoLuongMua * a.DonGia) < 5000 THEN 'Level 1'

  WHEN SUM(b.SoLuongMua * a.DonGia) >= 5000 AND SUM(b.SoLuongMua * a.DonGia) < 10000 THEN 'Level 2'

  WHEN SUM(b.SoLuongMua * a.DonGia) >= 10000 THEN 'V.I.P'

  ELSE 'Unknow'

  END

  FROM Item a JOIN CustomerItem b ON a.MaHang=b.Mahang JOIN Customer c ON b.MaKhach=c.MaKhach

  GROUP BY c.Ten;

Hoặc:

SELECT c.Ten, SUM(b.SoLuongMua * a.DonGia) AS [TongTienMua], CASE

  WHEN SUM(b.SoLuongMua * a.DonGia) < 5000 THEN 'Level 1'

  WHEN SUM(b.SoLuongMua * a.DonGia) >= 5000 AND SUM(b.SoLuongMua * a.DonGia) < 10000 THEN 'Level 2'

  WHEN SUM(b.SoLuongMua * a.DonGia) >= 10000 THEN 'V.I.P'

  ELSE 'Unknow'

  END AS [Level]

  FROM Item a JOIN CustomerItem b ON a.MaHang=b.Mahang JOIN Customer c ON b.MaKhach=c.MaKhach

  GROUP BY c.Ten;

 

TOP

Mệnh đề TOP dùng để lấy những bản ghi đầu tiên của tập kết quả từ câu lệnh SELECT. TOP cũng có thể được sử dụng với các câu lệnh INSERT, UPDATE và DELETE.

Dưới đây là cú pháp áp dụng cho trường hợp bạn muốn lấy một số lượng (n) cụ thể bản gì đầu tiên.

Cú pháp:

SELECT TOP(n) Các_cột FROM Các_bảng_liên_kết [WHERE Điều_kiện] ...;

Ví dụ: Để hiển thị thông tin của 3 khách hàng đầu tiên của bảng Customer ta làm như sau:

SELECT TOP(3) * FROM Customer;

Sử dụng mệnh đề TOP để tìm Max và Min

Nếu bạn muốn lấy giá trị lớn nhất (tìm max) trong một cột nào đó (ví dụ như lấy điểm cao nhất trong bảng điểm) thì bạn có thể làm như sau:

SELECT TOP(1) mark AS [Điểm cao nhất] FROM Marks ORDER BY mark DESC; --Sắp xếp theo thứ tự giảm => Điểm cao nhất sẽ là bản ghi đầu tiên trong tập kết quả

Vậy, nếu bạn muốn lấy điểm thấp nhất (tìm min) trong bảng điểm ta làm như sau:

SELECT TOP(1) mark AS [Điểm thấp nhất] FROM Marks ORDER BY mark ASC;

Practical 8

1. Tạo một file có tên Lab8.sql.

2. Tạo một CSDL có tên DBLab8.

3. Tạo ba bảng và chèn dữ liệu như sau:

Bảng Food lưu danh sách các món ăn gồm mã món ăn (fID), tên món ăn (Name), giá món ăn (Price):

fID (int, PK)

Name (nvarchar(30))

Price (money)

1

Gà hấp xì dầu

27000

2

Sườn nõn sốt chanh

33000

3

Bò xào hành tỏi

23000

4

Cá thu sốt

31000

Bảng FoodStuff lưu danh sách thực phẩm dùng để chế biến món ăn gồm mã thực phẩm (sID), tên thực phẩm (Name), loại thực phẩm (Type):

sID (int, PK)

Name (nvarchar(30))

Type (int)

1

Thịt  gà

1

2

Thịt lợn

1

3

Thịt bò

1

4

Cá thu

1

5

Hành

2

6

Tỏi

2

7

Cà chua

2

8

Xì dầu

2

9

Chanh

2

10

Hạt tiêu

2

Bảng FoodDetail mô tả các thực phẩm dùng để chế biến thành mỗi món ăn gồm fID, sID:

fID (int, FK tham chiếu tới fID của

            Food)

sID (int, FK tham chiếu tới sID của      FoodStuff)

1

1

1

8

2

2

2

9

2

7

2

5

3

3

3

5

3

6

4

4

4

7

4. Hiển thị tên các món ăn và tên các thực phẩm dùng để chế biến các món ăn đó:

 

Món ăn

Thực phẩm

1

Bò sào hành tỏi

Thịt bò

2

Bò sào hành tỏi

Hành

3

Bò sào hành tỏi

Tỏi

4

Cá thu sốt

Cá thu

5

Cá thu sốt

Cà chua

6

Gà hấp xì dầu

Thịt gà

7

Gà hấp xì dầu

Xì dầu

8

Sườn nõn sốt chanh

Thịt lợn

9

Sườn nõn sốt chanh

Hành

10

Sườn nõn sốt chanh

Cà chua

11

Sườn nõn sốt chanh

Chanh

 
5. Hiện danh sách những loại thực phẩm mà ko chế biến bất cứ món ăn nào như hình sau:
 

sID

Name

Type

10

Hạt Tiêu

2

 
6. Hiển thị tên những loại thực phẩm dùng cho nhiều hơn một món ăn như hình sau:
 

 

Name

1

Hành

2

Cà chua

 
7. Món ăn nào được chế biến từ nhiều loại thực phẩm nhất?
 

 

Name

1

Sườn nõn sốt chanh

 
8. Hiển thị danh sách các loại thực phẩm ra màn hình,trong đó trường Type hiện 'Thực phẩm chính' thay cho 1, và 'Gia vị' thay cho 2:
 

Name

Type

Thịt  gà

Thực phẩm chính

Thịt lợn

Thực phẩm chính

Thịt bò

Thực phẩm chính

Cá thu

Thực phẩm chính

Hành

Gia vị

Tỏi

Gia vị

Cà chua

Gia vị

Xì dầu

Gia vị

Chanh

Gia vị

Hạt tiêu

Gia vị

 
9. Tạo view tên là  vw_FoodList chứa danh sách các món ăn sắp xếp theo thứ tự giá tiền giảm dần:
 

 

fID

Name

Price

1

2

Sườn nõn sốt chanh

33000.000

2

4

Cá thu sốt

31000.000

3

1

Gà hấp xì dầu

27000.000

4

3

Bò sào hành tỏi

23000.000

 

10. Tăng giá các món ăn lên 10%. Sau đó hiển thị danh sách các món ăn và giá lên màn hình. Cuối cùng phục hồi lại giá ban đầu cho tất cả các món ăn.

11. Viết một thủ tục lưu trữ là sp_FoodChoice nhận vào 1 tham số là số tiền, thủ tục lữu trữ này sẽ hiển thị tất cả các món ăn có giá tiền nhỏ hơn số tiền được truyền vào.

12. Sửa thủ tục lưu trữ ở câu trên để nó có thể nhận vào 2 tham số, tham số thứ nhất là tên thực phẩm, tham số thứ 2 là phân loại món ăn theo 2 giá trị 'Rẻ' và 'Đắt'. Thủ tục lưu trữ sẽ hiện ra màn hình tất cả các món ăn và giá tiền thỏa mãn cả 2 điều kiện sau:

Điều kiện 1: Món ăn được chế biến từ các loại thực phẩm mà có tên tương tự tham số thứ nhất.

Điều kiện 2: Nếu tham số thứ 2 là 'Rẻ' thì chỉ lấy món ăn có giá nhỏ hơn 30000, nếu tham số thứ 2 là 'Đắt' thì chỉ lấy món ăn có giá lớn hơn hoặc bằng 30000, nếu tham số thứ 2 là '*' thì lấy các món ăn với giá bất kỳ.

Ví dụ, nếu chạy câu lệnh Exec FoodChoice 'Thịt', 'Rẻ' thì kết quả sẽ hiện ra như sau:

 

Name

Price

1

Gà hấp xì dầu

27000.000

2

Bò xào hành tỏi

23000.000

 

 13. Tạo một trigger tên là tg_NoUpdatePrice trên bảng Food, trigger này sẽ ngăn cản ko cho phép sửa (Update) giá món ăn thành giá trị lớn hơn hoặc bằng 40000, nếu người dùng cố tình sửa giá món ăn thành giá trị lớn hơn thì sẽ nhận được một thông báo 'Giá phải nhỏ hơn 40000'.

14. Tạo một trigger tên tg_delFood trên bảng Food sao cho khi 1 món ăn trong bảng Food bị xóa, trigger này sẽ xóa các thông tin liên quan đến món ăn đó trong bảng FoodDetail.

Xem thêm

TOP với PERCENT

Mệnh đề TOP với PERCENT dùng để lấy số lượng % bản ghi đầu tiên của tập kết quả từ câu lệnh SELECT.

Cú pháp:

SELECT TOP(n) PERCENT Các_cột FROM Các_bảng_liên_kết [WHERE Điều_kiện] ...;

Cú pháp trên sẽ lấy n% số bản ghi đầu tiên trong tập kết quả, trong đó n là một số thực nằm trong đoạn [0,100].

Mỗi bản ghi chiếm một tỷ lệ % trong tập kết quả là 100/Tập_kết_quả.

Ví dụ, nếu Tập_kết_quả là 10 bản ghi thì mỗi bản ghi chiếm tỷ lệ 100/10 = 10%. Như vậy, bản ghi đầu tiên sẽ nằm trong dải tỷ lệ là >0% đến 10%, bản ghi thứ hai có dải tỷ lệ là >10% đến 20%, ...

Ví dụ áp dụng:

Giả sử bảng Student có 10 bản ghi, ta có một số câu lệnh sau đây:

Lấy 15% số Sinh viên đầu tiên của tập kết quả:

SELECT TOP(15) PERCENT * FROM Student; -- 15% nằm trong dải tỷ lệ của bản ghi thứ 2, tức là câu lệnh này sẽ lấy được 2 bản ghi

Lấy 51.5% số Sinh viên đầu tiên của tập kết quả:

SELECT TOP(51.5) PERCENT * FROM Student; -- 51.5% nằm trong dải tỷ lệ của bản ghi thứ 6, tức là câu lệnh này sẽ lấy được 6 bản ghi

Hàm xử lý chuỗi

Dưới đây chúng ta sẽ tìm hiểu một số hàm xử lý chuỗi phổ dụng trong SQL Server. Các bạn cần lưu ý rằng các hàm này chỉ áp dụng được cho câu lệnh SELECT.

1. STR()

Hàm STR() trả về một chuỗi số từ một số hoặc một chuỗi số khác là đối số của hàm.

Cú pháp đơn giản:

STR(Số_hoặc_Chuỗi_số)

Cú pháp trên sẽ trả về một chuỗi số có độ chính xác là 0 và dành 10 khoảng độ rộng trường để chứa kết quả. Trong trường hợp kết quả có kích thước lớn hớn 10 thì hàm STR() sẽ trả về 10 ký tự dấu *.

Ví dụ:

SELECT STR(123456); --sẽ trả về chuỗi '123456'
SELECT STR(123.45); -- → '123'
SELECT STR(123.5); -- → '124'
SELECT STR(1234567890); -- → '1234567890'
SELECT STR(12345678901); --sẽ trả về chuỗi '**********' vì số có độ dài >10

Kết quả:

SQL - Hàm STR()

Khi bạn đặt số vào trong chuỗi thì kết quả cũng tương tự như trên:

SELECT STR('123456'); -- vẫn sẽ trả về chuỗi '123456'
SELECT STR('123.45'); -- → '123'
SELECT STR('123.5'); -- → '124'
SELECT STR('1234567890'); -- → '1234567890'
SELECT STR('12345678901'); -- → '**********'

Cú pháp đầy đủ:

STR(Số_hoặc_Chuỗi_số, Độ_rộng_trường, Độ_chính_xác)

Cú pháp trên sẽ cho phép bạn chủ động đưa ra độ rộng trường và độ chính xác mong muốn cho kết quả trả về.

Lưu ý :

+ Độ_rộng_trường bao gồm dấu (+ hoặc -), dấu chấm thập phân, các ký số và dấu cách.

+ Nếu kết quả có kích thước lớn hơn Độ_rộng_trường thì hàm STR() sẽ trả về chuỗi gồm Độ_rộng_trường ký tự *.

+ Nếu kết quả có kích thước nhỏ hơn Độ_rộng_trường thì hàm STR() sẽ trả về chuỗi kết quả và phía trước kết quả là số lượng khoảng trắng (space) tương ứng với độ lệch giữa Độ_rộng_trường và kích thước kết quả.

+ Độ_chính_xác tối đa cho phép đối với kết quả là 16 con số sau dấu chấm thập phân.

Dưới đây là một số ví dụ cho phần lưu ý trên:

SELECT STR(123456,5,1); --sẽ trả về chuỗi '*****'
SELECT STR(123456,6,1); -- → '123456'
SELECT STR(123456,7,1); -- → '123456'
SELECT STR(123456,8,1); -- → '123456.0'
SELECT STR(123456,10,1); -- → '  123456.0'

Kết quả:

SQL - Hàm STR() cú pháp đầy đủ

2. SUBSTRING()

SUBSTRING() dùng để lấy chuỗi con trong một chuỗi.

Cú pháp:

SUBSTRING('Chuỗi', Vị_trí, Số_lượng)

Ví dụ:

SELECT SUBSTRING('V1Study',2,3); --sẽ trả về chuỗi con '1St'

3. LEFT()

Hàm LEFT() dùng để lấy một số ký tự đầu tiên biên trái của một chuỗi.

Cú pháp:

LEFT('Chuỗi',Số_ký_tự)

Ví dụ:

SELECT LEFT('V1Study',2); --sẽ trả về chuỗi 'V1'

4. RIGHT()

RIGHT() dùng để lấy một số ký tự đầu tiên biên phải của một chuỗi.

Cú pháp:

RIGHT('Chuỗi',Số_ký_tự)

Ví dụ:

SELECT RIGHT('V1Study',5); --sẽ trả về chuỗi 'Study'

5. LEN()

Hàm LEN() dùng để lấy kích thước của một chuỗi.

Cú pháp:

LEN('Chuỗi')

Ví dụ:

SELECT LEN('V1Study'); --sẽ trả về số 7

6. LOWER()

Hàm LOWER() dùng để chuyển tất cả các ký tự in hoa trong một chuỗi thành in thường.

Cú pháp:

LOWER('Chuỗi')

Ví dụ:

SELECT LOWER('V1Study'); --sẽ trả về: 'v1study'

7. UPPER()

Hàm UPPER() dùng để chuyển tất cả các ký tự in thường trong một chuỗi thành in hoa.

Cú pháp:

UPPER('Chuỗi')

Ví dụ:

SELECT UPPER('V1Study'); --sẽ trả về: 'V1STUDY'

8. LTRIM()

Hàm LTRIM() dùng để xoá tất cả các ký tự trắng (space) ở đầu chuỗi.

Cú pháp:

LTRIM('Chuỗi')

Ví dụ:

SELECT LTRIM('   V1Study   '); --sẽ trả về: 'V1Study   '

9. RTRIM()

Hàm RTRIM() dùng để xoá tất cả các ký tự trắng (space) ở cuối chuỗi.

Cú pháp:

RTRIM('Chuỗi')

Ví dụ:

SELECT RTRIM('   V1Study   '); -- trả về chuỗi: '   V1Study'

10. ASCII()

Hàm ASCII() dùng để lấy vị trí trong bảng mã ASCII của một ký tự.

Cú pháp:

ASCII('Ký_tự')

Ví dụ:

SELECT ASCII('A'); -- → 65

Nếu trong cặp nháy đơn không phải là Ký_tự mà là một chuỗi thì hàm ASCII() sẽ lấy ký tự đầu tiên của chuỗi và trả về vị trí trong bảng mã ASCII của ký tự đó.

Ví dụ:

SELECT ASCII('abc123'); -- sẽ trả về số 97 (là vị trí của ký tự 'a')

11. CHAR()

CHAR() có tác dụng ngược với hàm ASCII(), nó dùng để lấy ký tự tương ứng vị trí trong bảng mã ASCII.

Cú pháp:

CHAR(Vị_trí)

Ví dụ:

SELECT CHAR(65); -- → 'A'

Nếu Vị_trí không có trong bảng mã ASCII thì hàm CHAR() sẽ trả về NULL.

12. STUFF()

STUFF() dùng để chèn một chuỗi vào một phần của chuỗi gốc và trả về chính chuỗi mới đó. Nó xóa số lượng ký tự xác định bắt đầu từ vị trí chỉ định rồi chèn chuỗi mong muốn vào đó.

Cú pháp:

STUFF('chuỗi_gốc', start, length, 'chuỗi_thêm_vào')

, trong đó:

- chuỗi_gốc: là chuỗi mà ta muốn thay đổi, có thể là hằng chuỗi, biến chuỗi hoặc một cột chứa dữ liệu chuỗi hoặc nhị phân.

- start: là một số nguyên thể hiện vị trí nơi xảy ra thay đổi, nếu start hay length là số âm thì hàm trả về chuỗi rỗng.

Ví dụ:

PRINT STUFF('abcdef', 2, 3, 'ijklmn');

Câu lệnh trên có nghĩa là thay thế 3 ký tự bắt đầu từ vị trí thứ 2 (tương đương với 'bcd') bằng chuỗi 'ijklmn'. Dưới đây là kết quả:

aijklmnef

13. SUBSTR()

Hàm này dùng cho MySQL có tác dụng lấy chuỗi bắt đầu từ ký tự thứ n.

Cú pháp:

SUBSTR('chuỗi_gốc', n)

, trong đó:

- chuỗi_gốc: là chuỗi mà ta muốn thay đổi, có thể là hằng chuỗi, biến chuỗi hoặc một cột chứa dữ liệu chuỗi hoặc nhị phân.

- n: là một số nguyên thể hiện vị trí nơi xảy ra thay đổi, nếu start hay length là số âm thì hàm trả về chuỗi rỗng.

Ví dụ:

PRINT SUBSTR('abcdef', 2);

Câu lệnh trên sẽ trả về chuỗi 'bcdef'.

TOP với WITH TIES

Mệnh đề TOP với WITH TIES dùng để lấy những bản ghi đầu tiên của tập kết quả từ câu lệnh SELECT, ngoài ra mệnh đề còn lấy thêm những bản ghi có giá trị /tập giá trị ở cột/tập cột bằng với giá trị/tập giá trị của bản ghi cuối cùng trong những bản ghi đầu tiên lấy được.

Cú pháp:

SELECT TOP(n) WITH TIES Các_cột FROM Các_bảng_liên_kết [WHERE Điều_kiện] ORDER BY Cột1, Cột2, ...;

, trong đó n là số lượng bản ghi đầu tiên muốn lấy trong tập kết quả.

Lưu ý rằng WITH TIES phải đi cùng với ORDER BY.

Ví dụ:

Giả sử bảng Marks có dữ liệu như sau:

studentid subjectid mark
1 1 24
1 2 24
2 1 25
2 2 25

Thì ta có các tình huống sau đây:

Lấy bản ghi có điểm số bé nhất trong bảng Marks:

SELECT TOP(1) * FROM Marks ORDER BY mark ASC; --Sắp xếp tăng dần theo cột mark => Bản ghi có điểm số nhỏ nhất nằm ở trên cùng

Ta được kết quả là: 

studentid subjectid mark
1 1 24

Lấy tất cả các bản ghi có điểm số bé nhất trong bảng Marks:

SELECT TOP(1) WITH TIES * FROM Marks ORDER BY mark ASC;

Ta được kết quả là: 

studentid subjectid mark
1 1 24
1 2 24

Giải thích: Vì cột mark ở bản ghi cuối cùng trong TOP(1) có giá trị 24 nên WITH TIES có nhiệm vụ lấy thêm những bản ghi có giá trị là 24 ở cột mark, và WITH TIES đã lấy được thêm 1 bản ghi thoả mãn.

Lấy bản ghi có điểm số lớn nhất trong bảng Marks:

SELECT TOP(1) * FROM Marks ORDER BY mark DESC--Sắp xếp giảm dần theo cột mark => Bản ghi có điểm số lớn nhất nằm ở trên cùng

Ta được kết quả là: 

studentid subjectid mark
2 1 25

Lấy tất cả các bản ghi có điểm số lớn nhất trong bảng Marks:

SELECT TOP(1) WITH TIES * FROM Marks ORDER BY mark DESC;

Ta được kết quả là: 

studentid subjectid mark
2 1 25
2 2 25

Bây giờ, ta lấy 3 điểm số nhỏ nhất của bảng Marks:

SELECT TOP(3) * FROM Marks ORDER BY mark ASC;

Ta được kết quả:

studentid subjectid mark
1 1 24
1 2 24
2 1 25

Bạn thấy ở bản ghi thứ 3 điểm số là 25, nhưng còn một bản ghi nữa cũng có điểm số là 25. Nếu bạn muốn lấy thêm những bản ghi có điểm số bằng với điểm số ở bản ghi thứ 3 (bản ghi cuối cùng trong TOP(3) có giá trị 25) ta làm như sau:

SELECT TOP(3) WITH TIES * FROM Marks ORDER BY mark ASC;

Ta được kết quả:

studentid subjectid mark
1 1 24
1 2 24
2 1 25
2 2 25
 
Tương tự, nếu bạn muốn lấy 3 bản ghi đầu tiên có giá trị điểm số lớn nhất và lấy thêm những bản ghi có giá trị điểm số bằng với điểm số thứ 3 trong tập kết quả ta làm như sau:
 

SELECT TOP(3) WITH TIES * FROM Marks ORDER BY mark DESC;

Ta được kết quả:

studentid subjectid mark
2 1 25
2 2 25
1 1 24
1 2 24

DELETE

Câu lệnh DELETE dùng để xóa bản ghi của bảng.

SQL không cho phép xóa bản ghi mà nó đang được tham chiếu đến từ bản ghi khác. Nếu bạn muốn xóa thì bạn có hai cách, hoặc là phải loại bỏ tham chiếu (loại bỏ khóa ngoại liên kết), hoặc là phải xóa bản ghi tham chiếu trước.

Ví dụ như bảng Student có bản ghi với mã sinh viên là 1, và ở bảng Marks tham chiếu (liên kết khóa ngoại) đến bảng Student có một bản ghi tham chiếu đến bản ghi này thì bạn không xóa được bản ghi với mã sinh viên là 1. Nếu muốn xóa bạn phải xóa khóa ngoại liên kết giữa bảng Marks với bảng Student, hoặc bạn phải xóa bản ghi tham chiếu trước.

Tuy nhiên, SQL lại cho phép xóa một cách tùy ý bản ghi nằm ở bảng tham chiếu.

Ví dụ như bạn được quyền xóa tùy ý những bản ghi nằm ở bảng Marks.

Trong trường hợp bạn muốn xóa tự động những bản ghi có liên quan đến nhau ở các bảng thì bạn có thể tham khảo phần kiến thức về TRIGGER.

Nếu bạn muốn xóa toàn bộ dữ liệu của một bảng ta có cú pháp như sau:

DELETE FROM Tên_bảng;

Ví dụ:

Xóa toàn bộ các bản ghi của bảng Marks:

DELETE FROM Marks;

Lưu ý là SQL không cho phép xóa nhiều bảng cùng lúc.

Nếu bạn muốn xóa một phần dữ liệu của bảng ta có cú pháp như sau:

DELETE FROM Tên_bảng WHERE Điều_kiện;

Ví dụ:

Xóa những bản ghi có mã sinh viên là 1 ở bảng Marks:

DELETE FROM Marks WHERE studentid=1;

Nếu bạn muốn xóa sinh viên có mã là 1 trong bảng Student bạn cần thực hiện các câu lệnh sau:

DELETE FROM Marks WHERE studentid=1; --Xóa những bản ghi có mã sinh viên là 1 ở bảng Marks trước,

DELETE FROM Student WHERE studentid=1; --rồi mới tiến hành xóa bản ghi có mã sinh viên là 1 ở bảng Student.

UPDATE

Câu lệnh UPDATE dùng để sửa (cập nhật) dữ liệu của bảng.

UPDATE thuộc ngôn ngữ thao tác dữ liệu DML (Data Manipulation Language).

Lưu ý rằng các giá trị được cập nhật trên cột nào phải thỏa mãn các ràng buộc đã được thiết lập trên cột đó (các ràng buộc cần lưu ý gồm PRIMARY KEY - PK, UNIQUECHECK và NOT NULL).

Cú pháp:

UPDATE Tên_bảng SET Tên_cột1=Giá_trị_mới1, Tên_cột2=Giá_trị_mới2, ... WHERE Điều_kiện;

Ví dụ:

UPDATE Marks SET mark=24 WHERE studentid=1 and subjecti=1; --sửa lại điểm thành 24 cho sinh viên có mã 1 và môn học có mã 1

Hàm .WRITE():

Hàm .WRITE() dùng trong câu lệnh UPDATE để sửa một phần giá trị dạng chuỗi.

Cú pháp:

UPDATE Tên_bảng SET Tên_cột .WRITE('Chuỗi_thay_thế', Vị_trí, Số_lượng) WHERE Điều_kiện;

, trong đó Vị_trí ở đây là vị trí nơi sẽ đặt 'Chuỗi_thay_thế', vị trí 0 là vị trí trước ký tự đầu tiên của chuỗi muốn sửa, chẳng hạn như vị trí 0 của chuỗi 'abc' là trước ký tự 'a', Số_lượng ở đây là số lượng ký tự muốn thay thế tính từ Vị_trí.

Ví dụ:

Giả sử bảng Student có bản ghi như sau:

studentid studentname
1 Nguyễn Hồng Hà

Bây giờ ta muốn sửa 'Nguyễn Hồng Hà' thành 'Trần Hồng Hà' thì ta làm như sau:

UPDATE Student SET studentname .WRITE(N'Trần', 0, 6) WHERE studentid=1;

Giải thích: vì chuỗi 'Trần' thay thế là chuỗi có dấu nên phải thể hiện thành N'Trần', vì muốn thay 'Nguyễn' thành 'Trần' nên vị trí đặt chuỗi thay thế là 0, và vì 'Nguyễn' có 6 ký tự nên số lượng ký tự cần thay thế là 6.

UPDATE với CASE-WHEN

Khi bạn muốn sửa dữ liệu với trường hợp có nhiều tình huống xảy ra, ví dụ như với ý 5 của bài tập Practical 6 thì bạn có thể áp dụng CASE-WHEN để thực hiện. Cú pháp áp dụng là như sau:

Cú pháp 1:

UPDATE Tên_bảng SET Tên_cột = CASE Tên_cột1

WHEN Giá_trị1 then Giá trị 1_1

WHEN Giá_trị2 then Giá trị 2_2

...

ELSE Giá_trị

END;

Cú pháp 2:

UPDATE Tên_bảng SET Tên_cột = CASE

WHEN Điều_kiện1 then Giá trị 1_1

WHEN Điều_kiện2 then Giá trị 2_2

...

ELSE Giá_trị

END;

Ví dụ, với ý 5 của bài tập Practical 6 ta có thể làm như sau:

UPDATE Projects SET Type = CASE

WHEN Cost<80 then 'Education'

WHEN Cost between 80 and 150 then 'Normal'

ELSE 'Goverment'

END;

Còn với ý 9 của bài tập Practical 5 ta làm như sau:

UPDATE Student SET Gender = CASE

WHEN Name in(N'Mỹ Linh', N'Tài Linh', N'Mỹ Lệ') then 0

WHEN Name = N'Kim Tử Long' then 1

END;

NOT

NOT được dùng trong trường hợp bạn muốn tìm những dữ liệu ngược với điều kiện. Cú pháp:

SELECT Các_cột FROM Các_bảng_liên_kết WHERE NOT Điều_kiện;

Ví dụ, nếu bạn muốn tìm những bạn sinh viên có mã  từ 4 trở xuống thì bạn có thể làm như sau:

SELECT * FROM Student WHERE NOT studentid>=5;

Còn đây là ví dụ tìm những sinh viên có họ và tên không phải là 'Nguyễn Văn A':

SELECT * FROM Student WHERE NOT studentname = N'Nguyễn Văn A';

Practical 9

Cho CSDL lưu trữ thông tin về quản lý sách ở  cửa hàng sách Rạng Đông ở Hà Nội gồm ba bảng có cấu trúc như sau:

Sach: Chứa danh sách các quyển sách có trong  cửa hàng Rạng Đông

Field

Description

MaSach

Mã sách, là Primary key

TenSach

Tên sách

TacGia

Tác giả

NhaXB

Tên nhà xuất bản

ChuDe

Chủ đề

DonGia

Đơn giá

TrongKho

Số lượng còn trong kho

 

Ví dụ,  bảng Sach có thể chứa các thông tin như sau:

MaSach

TenSach

TacGia

NhaXB

ChuDe

DonGia

TrongKho

1

Hoang hon tren song

Gia Phong

Van hoa

Tinh yeu

120

11

2

Cay lua nuoc

Le May

KHKT

Khoa hoc

30

24

3

Tam ly truoc mua thi

Hai Dang

Giao duc

Tam ly

42

32

 

KhachHang: Chứa danh sách khách hàng của cửa hàng

Field

Description

MaKH

Mã khách hàng, là Primary key

TenKH

Tên khách hàng

DiaChi

Địa chỉ kháchhàng

Quan

Tên quận hoặc huyện nơi khách hàng cư trú

DienThoai

Số điện thoại của kháchàng

NguoiGT

Người giới thiệu

 

Ví dụ,  bảng KhachHang có thể chứa các thông tin như sau:

MaKH

TenKH

DiaChi

Quan

DienThoai

NguoiGT

1

Le Cong

22 Hang Buom

Hoan Kiem

098123654

Hoang Kim

2

Van Nghe

19 Lo Duc

Hoan Kiem

 

 

3

Tran Thong

19 Doi Can

Ba Dinh

 

 

4

Hoang Tin

38 Linh Nam

Hoang Mai

 

 

 

SachBan: Chứa danh sách các quyển sách đã bán ở cửa hàng Rạng Đông.

Field

Description

SoHD

Số hóa đơn (là Primary key)

MaKH

Mã khách hàng đã mua sách

MaSach

Mã sách mà khách hàng đã mua

NgayMua

Ngày mua sách

DonGia

Đơn giá sách tại thời điểm bán sách

SoLuong

Số lượng sách bán

 

Ví dụ, bảng SachBan có thể chứa các thông tin như sau:

SoHD

MaKH

MaSach

NgayMua

DonGia

Soluong

1

1

2

22/11/2006

30

5

2

1

3

15/7/2005

 

4

3

2

1

24/5/2006

 

7

4

3

1

15/11/2005

 

9

 

Quan hệ giữa các bảng như sau:

Trong bảng SachBan thì field  MaKH là khóa ngoại tham chiếu đến field MaKH trong bảng KhachHang, còn field MaSach là khóa ngoại tham chiếu đến field MaSach trong bảng Sach.

Mô tả:

Trong bảng KhachHang thì mã số khách hàng (MaKH) là duy nhất, và các field dữ liệu về khách hàng là bắt buộc nhập (not NULL), ngoại trừ field NguoiGT.

Một khách hàng lần đầu tiên mua hàng ở của hàng sách Rạng Đông, nhân viên sẽ hỏi thông tin về khách hàng và nhập vào bảng KhachHang. Ví dụ, khách hàng là Tân đến mua sách ở Nhà Sách Rạng Đông thì thông tin về Tân có thể được lưu trữ trong bảng KhachHang như sau:

MaKH:              15

TenKH:             Tân

DiaChi:              123 Doi Can

Quan:                Ba Dinh

Dữ liệu mua sách sẽ được cập nhật vào bảng SachBan. Các field trong bảng này đều yêu cầu nhập dữ liệu (not NULL). Bảng Sach lưu các thông tin về từng đầu sách như đã giới thiệu ở trên.

Chú ý: Các thuộc tính có gạch chân là khoá chính (primary key) của bảng

YÊU CẦU:

Tạo database có tên RangDong và thực hiện các công việc sau:

Câu 1: Tạo bảng và nhập dữ liệu

a. Viết các câu SQL tạo bảng có đủ các khoá chính và khoá ngoại theo lược đồ và mô tả trên.

b. Viết các câu SQL nhập đầy đủ và chính xác những dữ liệu theo mô tả trên vào các bảng vừa tạo. (Lưu ý thứ tự nhập dữ liệu).         

Câu 2: Viết các câu truy vấn dữ liệu (query)

a. Viết câu lệnh SQL cho kết quả là số đầu sách xuất bản bởi nhà xuất bản “KHKT”.

b. Viết câu lệnh SQL cho kết quả là danh sách các nhà xuất bản cùng với số đầu sách tương ứng của từng NXB, theo thứ tự tăng dần của tên NXB

c. Viết câu lệnh SQL cho kết quả là danh sách các khách hàng sống trong quận "Ba Dinh", cùng với tên các đầu sách mà từng khách hàng đó đã mua.

d. Viết câu lệnh SQL cho kết quả là danh sách các khách hàng, cùng với tổng số các cuốn sách (total quantity) mà từng khách hàng đó đã mua.                                  

e. Viết câu lệnh SQL cho kết quả là danh sách các khách hàng, cùng với tên các nhà xuất bản của những đầu sách mà khách hàng đó đã mua.

f. Viết câu lệnh SQL cho kết quả là danh sách các khách hàng, cùng với số lần mua sách của từng khách hàng đó (mỗi record trong bảng SachBan là một lần mua sách).

g. Viết câu lệnh SQL cho kết quả là danh sách các quận, cùng với tổng giá trị mua sách của các khách hàng sống trong quận đó. Sắp xếp theo thứ tự giảm dần của giá trị.

IN() và NOT IN()

IN() được dùng trong trường hợp bạn muốn truy xuất những dữ liệu với điều kiện dữ liệu bao gồm các giá trị cụ thể nào đó.

Cú pháp IN():

IN(Giá_trị1, Giá_trị2, Giá_trị3, ...)

Ví dụ IN():

Nếu bạn muốn xem thông tin của những Sinh viên có mã 3, 5, 7 và 9 bạn làm như sau:

SELECT * FROM Student WHERE studentid IN(3, 5, 7, 9);

NOT IN() được dùng trong trường hợp bạn muốn truy xuất những dữ liệu với điều kiện dữ liệu không bao gồm các giá trị cụ thể nào đó.

Cú pháp NOT IN():

NOT IN(Giá_trị1, Giá_trị2, Giá_trị3, ...)

Ví dụ NOT IN():

- Nếu bạn muốn xem thông tin của những Sinh viên có mã không phải là 3, 5, 7 hay 9 bạn làm như sau:

SELECT * FROM Student WHERE studentid NOT IN(3, 5, 7, 9);

- Hiển thị những bạn học viên chưa thi môn nào (ý i. của bài tập Practical 2):

Những học viên chưa thi môn nào là những học viên có mã không nằm trong danh sách mã của bảng điểm (bảng StudentTest). Vậy, ta có câu lệnh như sau:

SELECT * FROM Student WHERE RN NOT IN(SELECT RN FROM StudentTest); 

BETWEEN và NOT BETWEEN

BETWEEN được dùng trong trường hợp bạn muốn truy xuất những dữ liệu với điều kiện dữ liệu nằm trong một đoạn (range) nào đó.

Cú pháp của BETWEEN:

BETWEEN Giá_trị1 AND Giá_trị2

Ví dụ cho BETWEEN:

Nếu bạn muốn lấy những Sinh viên có mã từ 2 đến 9 bạn làm như sau:

SELECT * FROM Student WHERE studentid BETWEEN 2 AND 9;

NOT BETWEEN có tác dụng ngược với BETWEEN, nghĩa là sẽ lấy dữ liệu với điều kiện dữ liệu không nằm trong đoạn nào đó.

Cú pháp NOT BETWEEN:

NOT BETWEEN Giá_trị1 AND Giá_trị2

Ví dụ NOT BETWEEN:

Nếu bạn muốn lấy những Sinh viên có mã không nằm trong đoạn từ 2 đến 9 bạn làm như sau:

SELECT * FROM Student WHERE studentid NOT BETWEEN 2 AND 9;

LIKE và NOT LIKE

LIKE được dùng trong trường hợp bạn muốn tìm dữ liệu tương tự hay gần giống với yêu cầu đề ra. Chẳng hạn nếu bạn muốn tìm những Sinh viên có tên là 'Anh' thì bạn sẽ cần dùng đến LIKE.

SQL đưa ra một số ký tự dạng đặc biệt sau đây khi áp dụng LIKE:

% : tương đương với một chuỗi bất kỳ.

_ : (dấu gạch dưới) tương đương với một ký tự bất kỳ.

[] : tương đương với một ký tự bất kỳ nằm trong cặp []. Ví dụ, [abc] tương đương với a hoặc b hoặc c.

[^] : tương đương với một ký tự bất kỳ không nằm trong cặp []. Ví dụ, [^abc] tương đương với một ký tự bất kỳ mà không phải a hay b hay c.

Ví dụ dưới đây sẽ tìm những sinh viên có họ là 'Hoàng':

SELECT * FROM Student WHERE studentname LIKE N'Hoàng %';

Tìm những sinh viên có tên là 'Anh':

SELECT * FROM Student WHERE studentname LIKE N'% Anh';

Tìm những sinh viên có tên gồm 3 ký tự:

SELECT * FROM Student WHERE studentname LIKE N'% ___'; -- 3 dấu gạch dưới

Tìm những sinh viên có tên có ký tự cuối là 'A' hoặc 'C':

SELECT * FROM Student WHERE studentname LIKE N'%[AC]';

Tìm những sinh viên có tên có ký tự cuối không phải là 'A' hoặc 'C':

SELECT * FROM Student WHERE studentname LIKE N'%[^AC]';

NOT LIKE lại có tác dụng ngược với LIKE, tức là nó được dùng trong trường hợp bạn không muốn tìm dữ liệu tương tự hay gần giống với yêu cầu đề ra. Chẳng hạn nếu bạn không muốn tìm những Sinh viên có tên là 'Anh' thì bạn sẽ dùng NOT LIKE.

Tìm những Sinh viên có họ không phải là 'Hoàng':

SELECT * FROM Student WHERE studentname NOT LIKE N'Hoàng %';

Tìm những Sinh viên có tên không phải là 'Anh':

SELECT * FROM Student WHERE studentname NOT LIKE N'% Anh';

EXISTS và NOT EXISTS

EXISTS

Hàm EXISTS() dùng để kiểm tra xem một câu lệnh SELECT nào đó (là đối số của hàm) có trả về bản ghi hay không. Nếu câu lệnh SELECT trả về ít nhất một bản ghi thì hàm EXISTS() sẽ trả về TRUE, ngược lại thì hàm trả về FALSE.

Cú pháp

EXISTS(subquery)

, trong đó, subquery là một câu lênh SELECT nhưng trong câu lệnh SELECT này không được dùng từ khóa INTO.

Kiểu trả về

boolean

Trả về TRUE nếu subquery trả về ít nhất một bản ghi.

Các ví dụ

Các ví dụ dưới đây sẽ sử dụng cơ sở dữ liệu mẫu AdventureWorks.

A. Sử dụng NULL trong subquery nhưng vẫn trả về một tập kết quả

Ví dụ sau đây trả về một tập kết quả trong đó subquery chứa NULL nhưng EXISTS vẫn trả về TRUE.

USE AdventureWorks

SELECT DepartmentID, Name
FROM HumanResources.Department
WHERE EXISTS (SELECT NULL)
ORDER BY Name ASC;

B. So sánh các truy vấn bằng cách sử dụng EXISTS và IN

Ví dụ sau đây so sánh hai truy vấn về mặt ngữ nghĩa là tương đương. Truy vấn đầu tiên sử dụng EXISTS và truy vấn thứ hai sử dụng IN.

USE AdventureWorks

SELECT a.FirstName, a.LastName
FROM Person.Person AS a
WHERE EXISTS
(SELECT *
    FROM HumanResources.Employee AS b
    WHERE a.BusinessEntityID = b.BusinessEntityID
    AND a.LastName = 'Johnson');
GO

Truy vấn sau đây sử dụng IN.

USE AdventureWorks

SELECT a.FirstName, a.LastName
FROM Person.Person AS a
WHERE a.LastName IN
(SELECT a.LastName
    FROM HumanResources.Employee AS b
    WHERE a.BusinessEntityID = b.BusinessEntityID
    AND a.LastName = 'Johnson');
GO

Dưới đây là tập kết quả mà cả hai câu truy vấn trên đều đưa ra như nhau.

FirstName LastName

-------------------------------------------------- ----------

Barry Johnson

David Johnson

Willis Johnson

(3 row(s) affected)

C. So sánh các truy vấn bằng cách sử dụng EXISTS và = ANY

Ví dụ sau đây thể hiện hai truy vấn đều nhằm mục đích tìm cửa hàng có tên là tên giống tên của nhà cung cấp. Truy vấn đầu tiên sử dụng EXISTS và truy vấn thứ hai sử dụng ANY.

USE AdventureWorks

SELECT DISTINCT s.Name
FROM Sales.Store AS s
WHERE EXISTS
(SELECT *
    FROM Purchasing.Vendor AS v
    WHERE s.Name = v.Name) ;
GO

Truy vấn sau đây sử dụng = ANY.

USE AdventureWorks

SELECT DISTINCT s.Name
FROM Sales.Store AS s
WHERE s.Name = ANY
(SELECT v.Name
    FROM Purchasing.Vendor AS v ) ;
GO

D. So sánh các truy vấn bằng cách sử dụng EXISTS và IN

Ví dụ sau đây thể hiện các truy vấn tìm nhân viên của các phòng ban bắt đầu bằng 'P'.

USE AdventureWorks

SELECT p.FirstName, p.LastName, e.JobTitle
FROM Person.Person AS p
JOIN HumanResources.Employee AS e
   ON e.BusinessEntityID = p.BusinessEntityID
WHERE EXISTS
(SELECT *
    FROM HumanResources.Department AS d
    JOIN HumanResources.EmployeeDepartmentHistory AS edh
       ON d.DepartmentID = edh.DepartmentID
    WHERE e.BusinessEntityID = edh.BusinessEntityID
    AND d.Name LIKE 'P%');
GO

Truy vấn sau đây sử dụng IN.

USE AdventureWorks

SELECT p.FirstName, p.LastName, e.JobTitle
FROM Person.Person AS p JOIN HumanResources.Employee AS e
   ON e.BusinessEntityID = p.BusinessEntityID
JOIN HumanResources.EmployeeDepartmentHistory AS edh
   ON e.BusinessEntityID = edh.BusinessEntityID
WHERE edh.DepartmentID IN
(SELECT DepartmentID
   FROM HumanResources.Department
   WHERE Name LIKE 'P%');
GO

NOT EXISTS

NOT EXISTS ngược với EXISTS. Mệnh đề WHERE trong NOT EXISTS được thỏa mãn nếu subquery không trả về bất kỳ bản ghi nào. Ví dụ sau đây tìm những nhân viên không phải là người của phòng ban có tên bắt đầu bằng 'P'.

USE AdventureWorks

SELECT p.FirstName, p.LastName, e.JobTitle
FROM Person.Person AS p
JOIN HumanResources.Employee AS e
   ON e.BusinessEntityID = p.BusinessEntityID
WHERE NOT EXISTS
(SELECT *
   FROM HumanResources.Department AS d
   JOIN HumanResources.EmployeeDepartmentHistory AS edh
      ON d.DepartmentID = edh.DepartmentID
   WHERE e.BusinessEntityID = edh.BusinessEntityID
   AND d.Name LIKE 'P%')
ORDER BY LastName, FirstName
GO

Dưới đây là tập hợp kết quả:

FirstName LastName Title

------------------------------ ------------------------------ ------------

Syed Abbas Pacific Sales Manager

Hazem Abolrous Quality Assurance Manager

Humberto Acevedo Application Specialist

Pilar Ackerman Shipping & Receiving Superviso

François Ajenstat Database Administrator

Amy Alberts European Sales Manager

Sean Alexander Quality Assurance Technician

Pamela Ansman-Wolfe Sales Representative

Zainal Arifin Document Control Manager

David Barber Assistant to CFO

Paula Barreto de Mattos Human Resources Manager

Shai Bassli Facilities Manager

Wanida Benshoof Marketing Assistant

Karen Berg Application Specialist

Karen Berge Document Control Assistant

Andreas Berglund Quality Assurance Technician

Matthias Berndt Shipping & Receiving Clerk

Jo Berry Janitor

Jimmy Bischoff Stocker

Michael Blythe Sales Representative

David Bradley Marketing Manager

Kevin Brown Marketing Assistant

David Campbell Sales Representative

Jason Carlson Information Services Manager

Fernando Caro Sales Representative

Sean Chai Document Control Assistant

Sootha Charncherngkha Quality Assurance Technician

Hao Chen HR Administrative Assistant

Kevin Chrisulis Network Administrator

Pat Coleman Janitor

Stephanie Conroy Network Manager

Debra Core Application Specialist

Ovidiu Crãcium Sr. Tool Designer

Grant Culbertson HR Administrative Assistant

Mary Dempsey Marketing Assistant

Thierry D'Hers Tool Designer

Terri Duffy VP Engineering

Susan Eaton Stocker

Terry Eminhizer Marketing Specialist

Gail Erickson Design Engineer

Janice Galvin Tool Designer

Mary Gibson Marketing Specialist

Jossef Goldberg Design Engineer

Sariya Harnpadoungsataya Marketing Specialist

Mark Harrington Quality Assurance Technician

Magnus Hedlund Facilities Assistant

Shu Ito Sales Representative

Stephen Jiang North American Sales Manager

Willis Johnson Recruiter

Brannon Jones Finance Manager

Tengiz Kharatishvili Control Specialist

Christian Kleinerman Maintenance Supervisor

Vamsi Kuppa Shipping & Receiving Clerk

David Liu Accounts Manager

Vidur Luthra Recruiter

Stuart Macrae Janitor

Diane Margheim Research & Development Enginee

Mindy Martin Benefits Specialist

Gigi Matthew Research & Development Enginee

Tete Mensa-Annan Sales Representative

Ramesh Meyyappan Application Specialist

Dylan Miller Research & Development Manager

Linda Mitchell Sales Representative

Barbara Moreland Accountant

Laura Norman Chief Financial Officer

Chris Norred Control Specialist

Jae Pak Sales Representative

Wanda Parks Janitor

Deborah Poe Accounts Receivable Specialist

Kim Ralls Stocker

Tsvi Reiter Sales Representative

Sharon Salavaria Design Engineer

Ken Sanchez Chief Executive Officer

José Saraiva Sales Representative

Mike Seamans Accountant

Ashvini Sharma Network Administrator

Janet Sheperdigian Accounts Payable Specialist

Candy Spoon Accounts Receivable Specialist

Michael Sullivan Sr. Design Engineer

Dragan Tomic Accounts Payable Specialist

Lynn Tsoflias Sales Representative

Rachel Valdez Sales Representative

Garrett Vargar Sales Representative

Ranjit Varkey Chudukatil Sales Representative

Bryan Walton Accounts Receivable Specialist

Jian Shuo Wang Engineering Manager

Brian Welcker VP Sales

Jill Williams Marketing Specialist

Dan Wilson Database Administrator

John Wood Marketing Specialist

Peng Wu Quality Assurance Supervisor

(91 row(s) affected)

Ví dụ sử dụng Azure SQL Data Warehouse Public Preview và Parallel Data Warehouse

F. Sử dụng EXISTS

USE AdventureWorks

SELECT a.LastName, a.BirthDate
FROM DimCustomer AS a
WHERE EXISTS
(SELECT *
    FROM dbo.ProspectiveBuyer AS b
    WHERE (a.LastName = b.LastName) AND (a.BirthDate = b.BirthDate));

G. Sử dụng NOT EXISTS

USE AdventureWorks

SELECT a.LastName, a.BirthDate
FROM DimCustomer AS a
WHERE NOT EXISTS
(SELECT *
    FROM dbo.ProspectiveBuyer AS b
    WHERE (a.LastName = b.LastName) AND (a.BirthDate = b.BirthDate));

Các phép toán so sánh

= : So sánh bằng

<> hoặc != : So sánh khác

> : So sánh lớn hơn

>= : So sánh lớn hơn hoặc bằng

< : So sánh nhỏ hơn

<= : So sánh nhỏ hơn hoặc bằng

Ví dụ:

Tìm những sinh viên có họ và tên là 'Nguyễn Văn A' :

SELECT * FROM Student WHERE studentname = N'Nguyễn Văn A';

Tìm những sinh viên có họ và tên không phải là 'Nguyễn Văn A' :

SELECT * FROM Student WHERE studentname <> N'Nguyễn Văn A';

Chỉ mục (INDEX)

Tổng quan

Giả sử bạn có một cuốn sách SQL và bạn muốn tìm phần kiến thức nói về GROUP BY, bạn có thể sử dụng hai cách, thứ nhất bạn bạn có thể tìm từ đầu đến cuối (hoặc từ cuối lên đầu) cuốn sách, thứ hai bạn tìm đến phần mục lục của cuốn sách rồi tra xem mục bạn muốn xem nằm ở trang nào.

Rõ ràng cách thứ hai sẽ khoa học và tốn ít thời gian tìm kiếm hơn cách thứ nhất, INDEX (hay Chỉ mục) tương tự như cách thứ hai.

Mỗi bảng trong SQL có thể được ví như một cuốn sách, mỗi bản ghi (hàng dữ liệu) của bảng có thể coi như một trang sách. INDEX sẽ có nhiệm vụ lập chỉ mục cho bảng.

Bạn biết rằng các bản ghi trong một bảng được lưu trữ theo thứ tự mà chúng được chèn (INSERT) vào bảng, trong đó bản ghi được chèn vào trước sẽ có vị trí trước, bản ghi được chèn vào sau có vị trí sau; có nghĩa rằng các bản ghi trong bảng không được sắp xếp, nếu vậy khi truy xuất dữ liệu (tìm kiếm) từ bảng thì hệ thống phải quét (scan) trên toàn bộ bảng, và điều này sẽ làm giảm đi tốc độ truy xuất dữ liệu.

Nhưng khi bạn tạo chỉ mục (index) cho bảng thì lại khác, index sẽ tiến hành tạo một thứ tự cho các bản ghi của bảng, và điều này sẽ giúp làm tăng tốc độ truy xuất dữ liệu.

Index for Table

Lưu ý

+ Bạn không nên tạo index nếu nó không được sử dụng thường xuyên, bởi vì để duy trì nó sẽ phải mất thời gian cũng như tài nguyên lưu trữ.

+ Bạn không nên tạo index trên cột hay tập cột có chứa những giá trị / tập giá trị giống nhau.

Cấu trúc INDEX

Cấu trúc Cây nhị phân (Binary-tree = B-tree):

b-tree

Cấu trúc INDEX dạng B-tree:

Index-B-tree-Structure

Về phân loại thì ta có hai loại INDEX cơ bản là Clustered IndexNonclustered Index. Hai loại INDEX này được trình bày chi tiết dưới đây.

Index-Clustered-NonClustered

Clustered Index

Clustered Index sẽ tiến hành lưu trữ các bản ghi của bảng ở mức vật lý rồi tiến hành sắp xếp chúng, nó thường áp dụng cho bảng chứa một lượng bản ghi lớn. Dữ liệu được lưu trữ theo cách sắp xếp trên khóa clustered và mỗi nút lá (leaf) của clustered index chứa một bản ghi.

Các đặc điểm sau đây cần lưu ý khi sử dụng Clustered Index:

- Mỗi bảng chỉ được phép có một Clustered Index.

- Khóa chính (Primary Key - PK) chính là một  Clustered Index.

- Clustered Index chỉ được tạo trên cột hoặc tập cột có chứa những giá trị hoặc tập giá trị duy nhất.

Giả sử ta có bảng Student gồm các cột sau: studentid (mã sinh viên), studentname (họ và tên), dateofbirth (ngày sinh), và email (email của sinh viên). Nếu bảng Student đã có PK thì bạn không thể tạo được Clustered Index trên nó vì PK chính là Clustered Index, muốn tạo bạn phải xóa PK. Nếu Student không có PK bạn có thể tạo được Clustered Index trên bảng này, nhưng nếu bạn định tạo trên cột studentname thì bạn cần xem lại vì cột này có thể có chứa nhiều sinh viên trùng tên; bạn có thể đặt Clustered Index trên cột email hoặc studentid là những cột chỉ chứa những giá trị duy nhất.

Cú pháp tạo Clustered Index như sau:

CREATE CLUSTERED INDEX Tên_index ON Tên_bảng(Các_cột);

Ví dụ, nếu bảng Student chưa có PK, ta thiết lập Clustered Index cho nó như sau:

CREATE CLUSTERED INDEX clus_student ON Student(studentid);

Nonclustered Index

Nonclustered Index được định nghĩa trên bảng trong đó dữ liệu có thể có cấu trúc phân cụm (clustered structure) hoặc ở dạng vun đống (heap).

Mỗi hàng index trong Nonclustered Index sẽ chứa một giá trị khóa nonclustered và một bộ định vị hàng.

Nonclustered Index thường áp dụng cho bảng chứa một lượng bản ghi nhỏ; một bảng có thể có nhiều Nonclustered Index.

Dữ liệu được lưu trữ theo cách sắp xếp trên khóa nonclustered và mỗi nút lá (leaf) của Nonclustered Index chứa một bản ghi.

Cú pháp tạo Nonclustered Index

CREATE NONCLUSTERED INDEX Tên_index ON Tên_bảng(Các_cột);

Hoặc:

CREATE INDEX Tên_index ON Tên_bảng(Các_cột);

Ví dụ, để tạo Nonclustered Index cho cột studentname của bảng Student, ta làm như sau:

CREATE NONCLUSTERED INDEX nonclus_student ON Student(studentname);

Hoặc:

CREATE INDEX nonclus_student ON Student(studentname);

Để tạo Nonclustered Index cho các cột studentname và dateofbirth của bảng Student, ta làm như sau:

CREATE NONCLUSTERED INDEX nonclus_student ON Student(studentname,dateofbirth);

Hoặc:

CREATE INDEX nonclus_student ON Student(studentname,dateofbirth);

Unique Index

Unique Index hay Unique Nonclustered Index dùng để tạo chỉ mục trên cột hay tập cột chứa những giá trị hoặc tập giá trị duy nhất.

Lưu ý: Khi đã tạo Unique Index trên cột hay tập cột của bảng thì sau đó bạn sẽ không thể chèn (INSERT) vào bảng này bản ghi có giá trị hay tập giá trị giống với bất kỳ giá trị hay tập giá trị đã được chèn trước đó.

Cú pháp:

CREATE UNIQUE NONCLUSTERED INDEX Tên_index ON Tên_bảng(Các_cột);

Hoặc:

CREATE UNIQUE INDEX Tên_index ON Tên_bảng(Các_cột);

Ví dụ, với bảng Student ở trên ta thấy rằng cột studentemail là cột chứa những email của sinh viên, những email này là duy nhất, tức là không có email giống nhau. Như vậy ta có thể tạo Unique Index trên cột này. Ta làm như sau:

CREATE UNIQUE NONCLUSTERED INDEX uninonclus_student ON Student(email);

Hoặc:

CREATE UNIQUE INDEX uninonclus_student ON Student(email);

Xoá Index

Để xoá Index ta sử dụng câu lệnh DROP INDEX. Đoạn mã dưới đây sẽ tiến hành xóa các index tương ứng của bảng Student:

DROP INDEX Student.clus_student;
DROP INDEX Student.nonclus_student;
DROP INDEX Student.uninonclus_student;

Xem thông tin Index

Nếu bạn muốn biết xem một bảng nào đó có những Index nào và thông tin cụ thể của nó ra sao bạn sử dụng sp_helpindex theo cú pháp sau:

EXEC sp_helpindex 'Tên_bảng';

Ví dụ:

EXEC sp_helpindex 'Student';

Khung nhìn (VIEW)

Tổng quan

Bạn đã biết đầu ra của câu lệnh SELECT là một tập kết quả thể hiện dưới dạng một bảng ảo, bạn có thể lưu trữ bảng ảo bằng cách sử dụng View (Khung nhìn). Những bảng từ đó khung nhìn được tạo được gọi là bảng cơ sở. Những bảng cơ sở này lại có thể là thuộc về các cơ sở dữ liệu khác nhau. Mỗi View có thể có tối đa 1024 cột và những hàng và cột của View được sinh ra ở dạng động khi View được tham chiếu.

View chỉ áp dụng cho câu lệnh SELECT, các cột của View cũng có thể được lấy từ các cột của View khác.

Bạn có thể có những thao tác trên View tương tự trên bảng như SELECT, INSERT, UPDATE, DELETE.

Phân loại View

Ta có thể có ba loại View cơ bản sau đây:

Standard View: View được tạo bao gồm các cột là các cột của các bảng hoặc các View khác.

Indexed View: View được tạo và được đặt chỉ mục Unique Clustered Index.

Partitioned View: View được tạo bao gồm các dữ liệu được phân cụm ngang từ một hoặc nhiều bảng.

Ưu điểm của View

  • Tăng tính bảo mật thông qua các truy cập được phân quyền riêng.
  • Cho phép tuỳ chỉnh việc hiển thị dữ liệu.
  • Cho phép gộp dữ liệu trên nhiều bảng và View.

System View (View hệ thống)

Các thuộc tính của các đối tượng như bảng hay View có thể được lưu trữ vào các bảng hệ thống đặc biệt gọi là metadata (siêu dữ liệu). Metadata có thể được xem thông qua System View (View hệ thống).

System View sẽ tự động được chèn vào cơ sở dữ liệu của người dùng, bạn có thể xem hình dưới đây để thấy được điều này:

System View

System View gồm các loại như: Catalog Views, Information Schema Views, Compatibility Views, Replication Views, Dynamic Management Views, Notification Services Views.

Tạo View

Cú pháp:

CREATE VIEW Tên_view AS Câu_lệnh_select;

Lưu ý: bạn không tạo được View mà trong đó có hai cột có tên giống nhau.

Ví dụ, tạo một View để xem thông tin của tất cả các sinh viên sinh năm 1995:

CREATE VIEW vw_ViewStudent AS
SELECT * FROM Student WHERE datepart(yy,dateofbirth)=1995;

Thực thi View

Vì View là một bảng ảo nên việc thực thi View tương tự như việc sử dụng câu lệnh SELECT đối với các bảng. Ví dụ bạn muốn thực thi View vw_ViewStudent ở trên bạn làm như sau:

SELECT * FROM vw_ViewStudent;

Sửa View

Bạn có thể sửa View bằng cách sử dụng câu lệnh ALTER VIEW, cú pháp như sau:

ALTER VIEW Tên_view AS Câu_lệnh_select;

Ví dụ, View vw_ViewStudent sẽ được sửa lại để nó chỉ bao gồm các cột studentid, studentname và dateofbirth:

ALTER VIEW vw_ViewStudent AS
SELECT studentid, studentname, dateofbirth FROM Student WHERE datepart(yy,dateofbirth)=1995;

Xoá View

Để xoá View ta sử dụng câu lệnh DROP VIEW. Ví dụ:

DROP VIEW vw_ViewStudent;

Xem định nghĩa View

Cách 1: Sử dụng thủ tục lưu trữ sp_helptext theo cú pháp sau:

EXEC sp_helptext 'Tên_view';

Ví dụ:

EXEC sp_helptext 'vw_ViewStudent';

Cách 2: Sử dụng hàm OBJECT_DEFINITION() theo cú pháp sau:

SELECT OBJECT_DEFINITION (OBJECT_ID('Tên_view'));

Ví dụ:

SELECT OBJECT_DEFINITION (OBJECT_ID('vw_ViewStudent'));

Cách 3: Sử dụng thủ tục lưu trữ sp_depends theo cú pháp sau:

EXEC sp_depends 'Tên_view';

Ví dụ:

EXEC sp_depends 'vw_ViewStudent';

Các tuỳ chọn khi tạo hoặc sửa View

WITH ENCRYPTION

Dùng để mã hoá định nghĩa View. Bạn sẽ không biết được View được định nghĩa như thế nào khi đã áp dụng tuỳ chọn này.

Cú pháp:

CREATE VIEW Tên_view WITH ENCRYPTION AS Câu_lệnh_select;
Hoặc áp dụng khi sửa View:
ALTER VIEW Tên_view WITH ENCRYPTION AS Câu_lệnh_select;

Ví dụ, ta sửa View vw_ViewStudent để không cho phép người dùng xem thông tin về nó, ta làm như sau:

ALTER VIEW vw_ViewStudent WITH ENCRYPTION AS
SELECT studentid, studentname, dateofbirth FROM Student WHERE datepart(yy,dateofbirth)=1995;

Thực thi:

EXEC sp_helptext 'vw_ViewStudent';

Kết quả:

The text for object 'vw_ViewStudent' is encrypted.

WITH CHECK OPTION

Dùng để đảm bảo rằng những giá trị áp dụng khi sửa (UPDATE) bản ghi qua View phải đáp ứng được điều kiện đã đặt ra trong quá trình tạo View.

Cú pháp:

CREATE VIEW Tên_view AS Câu_lệnh_select WITH CHECK OPTION;
Hoặc áp dụng khi sửa View:
ALTER VIEW Tên_view AS Câu_lệnh_select WITH CHECK OPTION;

Ví dụ, ta sửa View vw_ViewStudent để không cho phép người dùng xem thông tin về nó, ta làm như sau:

ALTER VIEW vw_ViewStudent AS
SELECT studentid, studentname, dateofbirth FROM Student WHERE datepart(yy,dateofbirth)=1995
WITH CHECK OPTION;

Thực thi:

Cập nhật trên cột dateofbirth của View vw_ViewStudent:

UPDATE vw_ViewStudent SET dateofbirth=getdate();

Kết quả là xuất hiện một lỗi với nội dung như sau:

Msg 550, Level 16, State 1, Line 1
The attempted insert or update failed because the target view either specifies WITH CHECK OPTION or spans a view that specifies WITH CHECK OPTION and one or more rows resulting from the operation did not qualify under the CHECK OPTION constraint.
The statement has been terminated.

Điều kiện ở câu lệnh SELECT đưa ra là năm phải = 1995, nhưng ở câu lệnh UPDATE thì năm sẽ là năm hiện tại (khác 1995), CHECK OPTION không cho phép làm điều này.

WITH SCHEMABINDING

View có thể được thiết lập ràng buộc vào giản đồ của các bảng được dùng để tạo ra nó bằng cách sử dụng WITH SCHEMABINDING. Khi đã thiết lập WITH SCHEMABINDING cho View rồi thì ta sẽ không thể sửa được cấu trúc của những cột dùng để tạo View nữa.

Cú pháp:

CREATE VIEW Tên_view WITH SCHEMABINDING AS Câu_lệnh_select;
Hoặc áp dụng khi sửa View:
ALTER VIEW Tên_view WITH SCHEMABINDING AS Câu_lệnh_select;

Lưu ý: Bạn cần nói rõ các bảng tham gia tạo View thuộc chủ sở hữu nào bằng cú pháp: Chủ_sở_hữu.Tên_bảng. Trong trường hợp không tạo chủ sở hữu (người dùng) thì chủ sở hữu mặc định là dbo (dbo.Tên_bảng). Ví dụ:

ALTER VIEW vw_ViewStudent WITH SCHEMABINDING AS
SELECT studentid, studentname, dateofbirth FROM dbo.Student WHERE datepart(yy,dateofbirth)=1995;

Thực thi:

ALTER TABLE Student ALTER COLUMN dateofbirth datetime; --sửa từ kiểu date thành datetime

Kết quả ta nhận được lỗi sau:

Msg 5074, Level 16, State 1, Line 1
The object 'vw_ViewStudent' is dependent on column 'dateofbirth'.
Msg 4922, Level 16, State 9, Line 1
ALTER TABLE ALTER COLUMN dateofbirth failed because one or more objects access this column.

Chú ý: Bạn có quyền thiết lập tất cả các tuỳ chọn cho View nếu cần thiết như ví dụ dưới đây:

ALTER VIEW vw_ViewStudent WITH ENCRYPTION, SCHEMABINDING AS
SELECT studentid, studentname, dateofbirth FROM dbo.Student WHERE datepart(yy,dateofbirth)=1995
WITH CHECK OPTION;

Tạo chỉ mục (INDEX) cho View

Để tạo chỉ mục cho một View nào đó bạn cần thiết lập tuỳ chọn WITH SCHEMABINDING cho View đó trước.

Lưu ý:

- Bạn chỉ thiết lập được Unique Clustered Index cho View, vì vậy cột hay tập cột của View được dùng để đặt chỉ mục phải chứa những giá trị hoặc tập giá trị duy nhất.

- Một điểm lưu ý nữa là bạn cần phải bỏ đi (nếu có) mệnh đề TOPORDER BY trước khi tạo chỉ mục cho View.

- Không tạo được index cho View khi View chứa mệnh để WHERE hoặc GROUP BY.

Cú pháp:

CREATE  | ALTER VIEW Tên_view WITH SCHEMABINDING AS Câu_lệnh_select;
CREATE UNIQUE CLUSTERED INDEX Tên_index ON Tên_view(Các_cột);

Ví dụ, ta tạo chỉ mục cho View vw_ViewStudent ở trên cho cột studentid như sau:

ALTER VIEW vw_ViewStudent WITH SCHEMABINDING AS
SELECT studentid, studentname, dateofbirth FROM dbo.Student WHERE datepart(yy,dateofbirth)=1995;
CREATE UNIQUE CLUSTERED INDEX uniclus_vw_ViewStudent ON vw_ViewStudent(studentid);

Sắp xếp trên View

Nếu bạn muốn tập kết quả của View được sắp xếp (ORDER BY) theo thứ tự tăng hay giảm của cột hay tập cột nào đó, bạn có thể sử dụng mệnh đề TOP(99.99) PERCENT ... ORDER BY như ví dụ dưới đây:

Ví dụ, ta sửa View vw_ViewStudent để tập kết quả trên View này sắp xếp theo chiều tăng dần của cột studentname (họ và tên sinh viên):

ALTER VIEW vw_ViewStudent AS
SELECT TOP(99.99) PERCENT studentid, studentname, dateofbirth FROM Student ORDER BY studentname ASC;

Practical 10

1. Tạo kiểu mytype từ kiểu varchar(40) not null.

2. Tạo bảng:

Book:

-BookCode: int, khoá chính , not null

-BookTitle: mytype

-Author: mytype

-Edition: int

-BookPrice: money

-Copies: int

Member:

-MemberCode: int, khóa chính, not null

-Name: mytype

-Address: mytype

-PhoneNumber: varchar(10)    

IssueDetails:

-BookCode: int, khóa ngoại trỏ tới BookCode của bảng Book

-MemberCode: int, khóa ngoại trỏ tới MemberCode của bảng Member

-IssueDate: datetime

-ReturnDate: datetime

3. Sửa đổi bảng:

- Thêm ràng buộc check: giá sách(BookPrice) phải lớn hơn 10

- Thêm cột IssueID kiểu uniqueidentifier

- Sửa đổi kiểu dữ liệu cho trường PhoneNumber thành kiểu varchar(12)

4. Chèn dữ liệu vào bảng:

Bảng Book:

sql-practical10-bang-book

Bảng Member:

sql-practical10-bang-member

 

Bảng IssueDetails:

- Dam Vinh Hung mượn quyển Guide To Advance Java ngày 10/9/2005, trả 10/20/2005

- My Le mượn quyển Java By Example ngày 1/1/2006 trả 1/5/2006

- Kim Tu Long mượn quyển EPC ngày 1/10/2006 trả 1/15/2006

- Tai Linh mượn quyển RDBMS ngày 1/20/2006 trả 1/25/2006

- Ung Hoang Phuc mượn quyển HTML ngày 2/1/2006 trả 2/5/2006

- My Linh mượn quyển  CF ngày 3/1/2006 trả 3/25/2006

5. Thực hiện các thao tác cập nhật

- Cập nhật bảng Member thêm trường Gender(giới tính) kiểu bit.

- Cập nhật giới tính cho Dam Vinh Hung, Kim Tu Long, Tai Linh, Ung Hoang Phuc la 1 cho My Le, My Linh là 0.

sql-practical10-cau-5

6. Đưa ra thống kê có mấy nam (gender = 1), mấy nữ (gender = 0).

sql-practical10-cau-6

7. Đưa ra tổng số sách trong thư viện.

sql-practical10-cau-7

8. Đưa ra những quyển sách có chữ cái 'C'.

sql-practical10-cau-8

9. Đưa ra những độc giả sống ở TP HCM.

sql-practical10-cau-9

10. Đưa ra những quyển sách được mượn năm 2006.

sql-practical10-cau-10

Thủ tục lưu trữ (SP)

Giới thiệu

Thủ tục lưu trữ (Stored Procedure - SP) là một nhóm các lệnh Transact-SQL (T-SQL) đóng vai trò như một khối lệnh đơn dùng để thực hiện một công việc (tác vụ) quản trị cụ thể hoặc áp dụng các luật giao dịch phức tạp.

Khối lệnh T-SQL được lưu trữ dưới một tên cụ thể, và vì vậy bạn có thể gọi SP cũng như tái sử dụng nó được nhiều lần. Ngoài ra, SP còn tăng tính bảo mật và giảm các giao dịch Khách/Chủ (Client/Server).

Trong SP bạn có quyền khai báo các biến, đưa vào các điều kiện và những đặc điểm lập trình khác.

Phân loại

Thủ tục lữu trữ gồm ba loại chính là: System SP (thủ tục lưu trữ hệ thống), Extended SP (thủ tục lưu trữ mở rộng) và User-defined SP (thủ tục lữu trữ do người dùng định nghĩa). Cụ thể:

System SP: Dùng để tương tác với các bảng hệ thống và thực hiện các tác vụ quản trị.

Extended SP: Loại SP này sẽ giúp cho SQL Server tương tác với Hệ điều hành (OS).

User-defined SP: Đây là thủ tục lưu trữ được định nghĩa bởi người dùng (lập trình viên), loại SP này còn được gọi là SP tuỳ chỉnh. Dưới đây là hướng dẫn chi tiết gồm cách tạo, sửa và xóa đối với loại SP này.

Tạo thủ tục lưu trữ

Cú pháp:

CREATE PROC | PROCEDURE Tên_SP(Danh_sách_tham_số) [WITH ENCRYPTION | RECOMPILE, ENCRYPTION | ECOMPILE] AS
BEGIN
  [Khai_báo_các_biến_cục_bộ_của_SP]
  Khối_lệnh_T-SQL;
END;

Mỗi SP có quyền truy cập đến tất cả các đối tượng mỗi khi nó được gọi. Bạn có có thể sử dụng tới 2100 tham số trong Danh_sách_đối_số đối với mỗi SP. Dung lượng tối đa cho mỗi SP là 128MB.

Giả sử ta có 3 bảng dữ liệu sau đây:

Bảng Customer (lưu trữ thông tin của Khách hàng):

CustomerID (int) Name (varchar(30)) Birth (date) Gender (bit)
1 Johny Owen 10/10/1980 1
2 Christina Tiny 10/03/1989 0
3 Garry Kelley 16/03/1990 Null
4 Tammy Beckham 17/05/1980 0
5 Divid Phantom 30/12/1987 1

Bảng Product (lưu trữ thông tin Sản phẩm):

ProductID (int) Name (varchar(30)) Pdesc (text) Pimage (varchar(200)) Pstatus (bit)
1 Nokia N90 Mobile Nokia image1.jpg 1
2 HP DV6000 Laptop image2.jpg Null
3 HP DV2000 Laptop iamge3.jpg 1
4 SamSung G488 Mobile SamSung image4.jpg 0
5 LCD Plasma TV LCD image5.jpg 0

Bảng Comment (lưu trữ bình luận của Khách đối với Sản phẩm). Ví dụ: bản ghi đầu tiên của bảng dưới thể hiện rằng 'Jonny Owen' (mã là 1 ở bảng Customer) đã bình luận cho sản phẩm ‘Nokia N90’ (mã là 1 ở bảng Product) vào ngày '15/03/09').

ComID (int identity(1,1)) ProductID (int) CustomerID (int) Date (datetime) Title (varchar(200) Content (text) Status (bit)
1 1 1 15/03/09 Hot product Null 1
2 2 2 14/03/09 Hot price Very much 0
3 3 2 20/03/09 Cheapest Unlimited 0
4 4 2 16/04/09 Sale off 50% 1

Dưới đây sẽ là một số ví dụ cho việc tạo thủ tục lưu trữ sử dụng các bảng trên:

· Tạo SP có tên 'sp_Product' có một tham số tên @productid, nếu tìm thấy @productid trong cột ProductID của bảng Product thì hiển thị tất cả thông tin liên quan đến sản phẩm tương ứng, nếu không thì đưa ra thông báo 'Không tìm thấy sản phẩm có mã @productid'. Ta làm như sau:

CREATE PROC sp_Product(@productid int) AS
BEGIN
  IF(exists(SELECT * FROM Product WHERE productid=@productid))
    SELECT * FROM Product WHERE productid=@productid
  ELSE
    print N'Không tìm thấy sản phẩm có mã ' + str(@productid,3);
END;

Thực thi:

EXEC sp_Product 1; --Có thể bỏ EXEC

 

Thực thi:

EXEC sp_Product 6;

Kết quả:

Không tìm thấy sản phẩm có mã  6

· Tạo thủ tục lưu trữ có tên 'spSearchProduct' có một tham số tên @Name:

- Nếu tìm thấy @Name trong cột Name của bảng Product thì sẽ liệt kê tất cả những bình luận cho những Sản phẩm có tên tương tự (like) @Name.

- Nếu không thì kiểm tra @Name nếu tìm thấy trong Name của bảng Customer thì sẽ liệt kệ tất cả những bình luận của những Khách có tên tương tự (like) @Name.

- Còn nếu @Name nhận giá trị '*' thì sẽ liệt kê tất cả các bình luận đang có.

Đối với yêu cầu này ta làm như sau:

CREATE PROC sp_SearchProduct(@Name VARCHAR(30)) AS
BEGIN
  IF(EXISTS(SELECT Name FROM Product WHERE Name like '%'+@Name+'%'))
    SELECT Name, [Date], Title, Content, [Status] FROM Product a JOIN Comment b ON a.ProductID=b.ProductID WHERE Name like '%'+@Name+'%';
  ELSE IF(@Name = '*')
    SELECT Name, [Date], Title, Content, [Status] FROM Product a JOIN Comment b ON a.ProductID=b.ProductID ;    
  ELSE
    print N'Không tìm thấy sản phẩm có tên tương tự '+@Name;
END;

Thực thi:

EXEC sp_SearchProduct 'No';

Thực thi:

EXEC sp_SearchProduct 'No1';

Kết quả:

Không tìm thấy sản phẩm có tên tương tự No1

Thực thi:

EXEC sp_SearchProduct '*';

· Tạo thủ tục lưu trữ có tên 'spDropOut' có một  tham số là tên của Khách hàng, nếu tìm thấy tên này trong cột Name của bảng Customer thì sẽ xóa tất cả những thông tin của tất cả những Khách hàng có tên tương ứng đó trên tất cả các bảng liên quan của Cơ sở dữ liệu. Ta xử lý yêu cầu này như sau:

CREATE PROC spDropOut(@customerName varchar(30)) AS
BEGIN
  IF(EXISTS(SELECT Name FROM Customer WHERE Name=@customerName))
  BEGIN
    DELETE FROM Comment WHERE CustomerID IN(SELECT CustomerID FROM Customer WHERE Name=@customerName)
    DELETE FROM Customer WHERE Name=@customerName
  END;
  ELSE
    print N'Không tìm thấy khách hàng có tên '+@customerName;
END;

Thực thi:

EXEC spDropOut 'Jonny Owen';

Kết quả:

(1 row(s) affected)
(1 row(s) affected)

Thực thi:

EXEC spDropOut 'Michael Obama';

Kết quả:

Không tìm thấy khách hàng có tên Michael Obama

Sửa thủ tục lưu trữ

Để sửa một thủ tục lưu trữ tùy chỉnh ta sử dụng câu lệnh ALTER theo cú pháp như sau:

ALTER PROC | PROCEDURE Tên_SP(Danh_sách_tham_số) [WITH ENCRYPTION | RECOMPILE, ENCRYPTION | ECOMPILE] AS
BEGIN
  [Khai_báo_các_biến_cục_bộ_của_SP]
  Khối_lệnh_T-SQL;
END;

Ví dụ, giả sử ta tạo một SP để xem thông tin của tất cả các Khách hàng (bảng Customer ở trên), ta làm như sau:

CREATE PROC sp_ViewCustomer AS
BEGIN
  SELECT * FROM Customer;
END;

Bây giờ ta cần sửa SP trên để nó chỉ cho phép xem thông tin của các Khách hàng có năm sinh được nhập từ bàn phím, ta làm như sau:

ALTER PROC sp_ViewCustomer(@year varchar(4)) AS
BEGIN
  SELECT * FROM Customer WHERE datepart(year,Birth)=@year;
END;

Thực thi:

EXEC sp_ViewCustomer 1980;

Còn bây giờ ta muốn ngăn không cho người dùng xem thông tin của SP sp_ViewCustomer ta làm như sau:

ALTER PROC sp_ViewCustomer(@year varchar(4)) WITH ENCRYPTION AS
BEGIN
  SELECT * FROM Customer WHERE datepart(year,Birth)=@year;
END;

Thực thi:

EXEC sp_helptext 'sp_ViewCustomer';

Kết quả:

The text for object 'sp_ViewCustomer' is encrypted.

Xóa thủ tục lưu trữ

Để xoá một SP tùy chỉnh ta sử dụng câu lệnh DROP PROC. Câu lệnh sau sẽ xóa thủ tục lưu trữ sp_ViewCustomer:

DROP PROC sp_ViewCustomer;

Lưu ý rằng bạn không xóa được thủ tục lưu trữ hệ thống nếu bạn không có quyền.

Xem thông tin thủ tục lưu trữ

Bạn có thể xem thông tin của bất kỳ loại SP nào (bao gồm cả SP hệ thống) nếu SP đó chưa mã hóa.

Cách 1: Sử dụng SP sp_helptext, thông tin chi tiết về định nghĩa SP sẽ được thể hiện đúng như nó được viết trong code. Cú pháp như sau:

EXEC sp_helptext 'Tên_SP';

Ví dụ:

EXEC sp_helptext 'sp_ViewCustomer'; --Xem định nghĩa SP tùy chỉnh
EXEC sp_helptext 'sp_columns'; --Xem định nghĩa System SP

Cách 2: Sử dụng hàm OBJECT_DEFINITION(), thông tin chi tiết về định nghĩa SP sẽ được thể hiện trên một hàng. Cú pháp:

SELECT OBJECT_DEFINITION( OBJECT_ID('Tên_SP');

Ví dụ:

SELECT OBJECT_DEFINITION( OBJECT_ID('sp_ViewCustomer'));
SELECT OBJECT_DEFINITION( OBJECT_ID('sp_columns'));

Cách 3: Sử dụng sys.sql_modules, cách này không áp dụng cho thủ tục lưu trữ hệ thống. Cú pháp sử dụng như sau:

SELECT definition FROM sys.sql_modules WHERE object_id = OBJECT_ID('Tên_SP');

Ví dụ:

SELECT definition FROM sys.sql_modules WHERE object_id = OBJECT_ID('sp_ViewCustomer');

Cách 4: Sử dụng thủ tục lưu trữ sp_depends, cách này dùng để xem sự phụ thuộc của thủ tục lữu trữ vào các thành phần như Bảng, View. Cú pháp:

EXEC sp_depends 'Tên_SP';

Ví dụ, nếu ta thực hiện câu lệnh EXEC sp_depends 'sp_ViewCustomer';, thì kết quả sẽ như hình dưới đây:

http://v1study.com/public/images/article/sql-sp-exam5.png

Cơ bản về Trigger

Giới thiệu

Trigger là một thủ tục lưu trữ được thực hiện khi có một nỗ lực để sửa đổi dữ liệu trong bảng được bảo vệ bằng trigger. Không giống như các thủ tục lưu trữ hệ thống tiêu chuẩn, ta không thể thực thi các trigger trực tiếp, chúng cũng không truyền hoặc nhận các tham số. Trigger được định nghĩa trên các bảng cụ thể và những bảng này được gọi là bảng trigger.

Nếu trigger được định nghĩa trên hành động INSERT, UPDATE hoặc DELETE trên một bảng, thì nó sẽ tự hủy khi những hành động này được thực thi. Sự thực thi tự động này của trigger không thể bị phá vỡ. Trong SQL Server, trigger được tạo ra bằng cách sử dụng câu lệnh CREATE TRIGGER. Hình dưới đây thể hiện ví dụ về trigger.

sql: giới thiệu trigger

Cách dùng trigger

Trigger có thể chứa logic xử lý phức tạp và thường được sử dụng để duy trì tính toàn vẹn dữ liệu ở mức độ thấp. Dưới đây là một số cách dùng trigger có thể được phân loại như sau:

Phân tầng thay đổi thông qua các bảng liên quan

Người dùng có thể sử dụng một trigger cho các thay đổi tầng thông qua các bảng liên quan. Ví dụ, ta có bảng Salary_Details có khóa ngoại (FOREIGN KEY) nằm trên cột EmpID và tham chiếu tới khóa chính (PRIMARY KEY) là EmpID của bảng Employee_Details. Nếu sự kiện cập nhật hoặc xóa xảy ra trong bảng Employee_Details, thì trigger UPDATE hoặc DELETE có thể được định nghĩa để xếp tầng những thay đổi đối với bảng Salary_Details.

Thực thi toàn vẹn dữ liệu phức tạp hơn ràng buộc CHECK

Không giống như các hạn chế CHECK, trigger có thể tham khảo các cột trong các bảng khác. Tính năng này có thể được sử dụng để áp dụng các kiểm tra tính toàn vẹn dữ liệu phức tạp. Tính toàn vẹn dữ liệu có thể được thực thi bằng cách:

+ Kiểm tra các ràng buộc trước khi xếp tầng các cập nhật hoặc xóa.

+ Tạo ra các trigger nhiều hàng cho các hành động được thực hiện trên nhiều hàng.

+ Thực thi tính toàn vẹn tham chiếu giữa các cơ sở dữ liệu.

Định nghĩa các thông báo lỗi tùy chỉnh

Các thông báo lỗi tùy chỉnh được sử dụng để cung cấp lời giải thích phù hợp hoặc chi tiết hơn trong các tình huống lỗi nhất định. Có thể sử dụng các trigger để gọi các thông báo lỗi tùy chỉnh được xác định trước như vậy khi các điều kiện lỗi có liên quan xảy ra.

Duy trì dữ liệu không chuẩn hóa

Tính toàn vẹn dữ liệu mức thấp có thể được duy trì trong các môi trường cơ sở dữ liệu không chuẩn hóa sử dụng các trigger. Dữ liệu không chuẩn hóa thường đề cập đến dữ liệu dư thừa hoặc bắt nguồn. Ở đây, các trigger được sử dụng cho các kiểm tra không yêu cầu các so khớp chính xác. Ví dụ, nếu giá trị của năm sẽ được kiểm tra đối với các ngày hoàn tất, trigger có thể được sử dụng để thực hiện kiểm tra.

So sánh các trạng thái trước và sau của dữ liệu đang được sửa đổi

Trigger cung cấp tùy chọn này để tham khảo các thay đổi được thực hiện cho dữ liệu bằng các câu lệnh INSERT, UPDATE và DELETE. Điều này cho phép người dùng tham khảo các hàng bị ảnh hưởng khi các sửa đổi được thực hiện thông qua các trigger.

Phân loại trigger

Trigger có thể được đặt để thực thi tự động một hành động khi một sự kiện ngôn ngữ xảy ra trong một bảng hoặc khung nhìn. Các sự kiện ngôn ngữ có thể được phân loại là các sự kiện DML và các sự kiện DDL. Trigger liên quan đến các sự kiện DML được gọi là trigger DML, trong khi trigger kết hợp với các sự kiện DDL được gọi là trigger DDL.

Trigger trong SQL Server có thể được phân thành ba loại cơ bản:

- Trigger DML

Các trigger DML (Data Manipulation Language) được thực thi khi dữ liệu được chèn, sửa đổi hoặc xóa trong một bảng hoặc khung nhìn sử dụng câu lệnh INSERT, UPDATE hoặc DELETE.

- Trigger DDL

Các trigger DDL (Data Definition Language) được thực thi khi một bảng hoặc khung nhìn được tạo ra, chỉnh sửa hoặc xóa bằng cách sử dụng câu lệnh CREATE, ALTER hoặc DROP.

- Trigger đăng nhập (Logon)

Các trigger đăng nhập sẽ thực thi các thủ tục lưu trữ khi một phiên được thiết lập với một sự kiện LOGON. Những trigger này được gọi sau khi chứng thực đăng nhập được hoàn thành và trước khi phiên thực tế được thiết lập. Các trigger đăng nhập kiểm soát các phiên máy chủ bằng cách hạn chế các thông tin đăng nhập không hợp lệ hoặc hạn chế số lượng phiên.

So sánh trigger DDL và trigger DML

Các trigger DDL và DML có cách sử dụng khác nhau và được thực thi với các sự kiện cơ sở dữ liệu khác nhau. Bảng dưới đây liệt kê ra những khác biệt giữa các trigger DDL và DML.

Trigger DDL Trigger DML
Các trigger DDL thực thi các thủ tục lưu trữ trên câu lệnh CREATE, ALTER và DROP. Các trigger DML thực thi trên các câu lệnh INSERT, UPDATE và DELETE.
Các trigger DDL được sử dụng để kiểm tra và kiểm soát các hoạt động của cơ sở dữ liệu. Các trigger DML được sử dụng để thực thi các quy tắc thương mại khi dữ liệu được sửa đổi trong các bảng hoặc khung nhìn.
Các trigger DDL chỉ hoạt động sau khi bảng hoặc khung nhìn được sửa đổi. Các trigger DML thực thi trong hoặc sau khi dữ liệu được sửa đổi.
Các trigger DDL được định nghĩa ở mức cơ sở dữ liệu hoặc máy chủ. Các trigger DML được định nghĩa ở mức cơ sở dữ liệu.

Tạo các trigger DML

Các trigger DML được thực thi khi sự kiện DML xảy ra trong các bảng hoặc khung nhìn. Những sự kiện DML này bao gồm các câu lệnh INSERT, UPDATE và DELETE. Các trigger DML có thể thực thi khi hoàn thành các sự kiện DML hoặc ở vị trí của các sự kiện DML.

Các trigger DML bắt buộc tính toàn vẹn tham chiếu bằng cách xếp tầng các thay đổi tới các bảng có liên quan khi một hàng được sửa đổi. Các trigger DML có thể thực hiện nhiều hành động cho mỗi câu lệnh sửa đổi.

Các trigger DML gồm ba loại chính:

· Trigger INSERT

· Trigger UPDATE

· Trigger DELETE

sql: trigger DML
Các loại trigger DML

Giới thiệu về các bảng Inserted và Deleted

Những câu lệnh SQL trong các trigger DML sử dụng hai loại bảng đặc biệt để sửa đổi dữ liệu trong cơ sở dữ liệu. Khi dữ liệu được chèn, cập nhật hoặc xóa thì SQL Server tạo ra và quản lý những bảng này một cách tự động. Các bảng tạm thời lưu trữ dữ liệu ban đầu cũng như dữ liệu đã sửa đổi. Những bảng này gồm Inserted và Deleted.

Bảng Inserted

Bảng Inserted chứa bản sao các bản ghi được sửa đổi với hoạt động INSERT và UPDATE trên bảng trigger (bảng trigger là bảng trên đó trigger được định nghĩa). Hoạt động INSERT và UPDATE sẽ tiến hành chèn các bản ghi mới vào bảng Inserted và bảng trigger.

Bảng Deleted

Bảng Deleted chứa bản sao của các bản ghi được sửa đổi với hoạt động DELETE và UPDATE trên bảng trigger. Những hoạt động này sẽ xóa các bản ghi từ bảng trigger và chèn chúng vào bảng Deleted.

Chú ý: Bảng Inserted và Deleted về khía cạnh vật lý chúng không tồn tại trong cơ sở dữ liệu. Chúng được tạo ra và hủy bỏ bất cứ khi nào với bất kỳ sự kiện kích hoạt nào xảy ra.

Trigger INSERT

Trigger INSERT được thực thi khi một bản ghi mới được chèn vào bảng. Trigger INSERT đảm bảo rằng giá trị đang được nhập phù hợp với các ràng buộc được định nghĩa trên bảng đó.

Khi người dùng chèn một bản ghi vào bảng tương ứng, thì trigger INSERT sẽ lưu một bản sao của bản ghi đó vào bảng Inserted. Sau đó nó sẽ kiểm tra xem giá trị mới trong bảng Inserted phù hợp với các ràng buộc đã chỉ định hay không. Nếu bản ghi hợp lệ, trigger INSERT tiến hành chèn nó vào bảng trigger, nếu không nó sẽ hiển thị thông báo lỗi.

Trigger INSERT được tạo ra bằng cách sử dụng từ khóa INSERT trong câu lệnh CREATE TRIGGER và ALTER TRIGGER.

Sau đây là cú pháp cho việc tạo ra trigger INSERT:

CREATE TRIGGER [schema_name.] trigger_name ON [schema_name.] table_name [WITH ENCRYPTION] {FOR INSERT} AS
[IF UPDATE (column_name)...]
[{AND | OR} UPDATE (column_name)...]
<sql_statements>

, trong đó:

schema_name: chỉ ra tên của lược đồ có chứa bảng/trigger đó.

trigger_name: chỉ ra tên của trigger do người dùng tự đặt.

table_name: chỉ ra bảng mà trên đó trigger DML được tạo ra (bảng trigger).

WITH ENCRYPTION: mã hóa văn bản của câu lệnh CREATE TRIGGER.

FOR: chỉ ra rằng trigger DML thực thi sau khi các hoạt động sửa đổi được hoàn tất.

INSERT: chỉ ra rằng trigger DML này sẽ được gọi bởi các hoạt động chèn.

UPDATE: trả về giá trị Boolean cho biết xem hành động INSERT hoặc UPDATE đã được thực hiện hay chưa trên một cột cụ thể.

column_name: là tên của cột để kiểm tra về hành động UPDATE.

AND: Kết hợp hai biểu thức Boolean và trả về TRUE khi cả hai biểu thức là TRUE.

OR: Kết hợp hai biểu thức Boolean và trả về TRUE nếu ít nhất một biểu thức là TRUE.

sql_statement: chỉ ra các câu lệnh SQL được thực thi trong trigger DML.

Đoạn mã dưới đây sẽ tạo ra trigger INSERT có tên CheckWithdrawal_Amount trên bảng có tên là Account_Transactions. Khi một bản ghi mới được đưa vào, và nếu số tiền rút vượt quá 80000 thì trigger INSERT sẽ hiển thị thông báo lỗi và quay lui giao tác sử dụng câu lệnh ROLLBACK TRANSACTION (giao tác là tập hợp một hoặc nhiều câu lệnh được xử lý như một đơn vị công việc. Giao tác có thể thành công hoặc thất bại, do đó tất cả các câu lệnh trong đó cùng thành công hay thất bại. Câu lệnh ROLLBACK TRANSACTION được dùng khi muốn hủy bỏ hoặc quay lui một giao tác).

CREATE TRIGGER CheckWithdrawal_Amount ON Account_Transactions FOR INSERT AS
IF (SELECT Withdrawal From inserted) > 80000
BEGIN
PRINT 'Số tiền rút không thể vượt quá 80000.'
ROLLBACK TRANSACTION
END

Đoạn mã sau đây sẽ chèn một bản ghi trong đó Số tiền rút (Withdrawal) là 90000. Điều này làm cho trigger INSERT hiển thị thông báo lỗi và quay lui giao tác.

INSERT INTO Account_Transactions
(TransactionID, EmployeeID, CustomerID, TransactionTypeID, TransactionDate, TransactionNumber, Deposit, Withdrawal)
VALUES (1008,'E08','C08','T08','05/02/12','TN08', 300000,90000)

Thông báo lỗi sau được hiển thị như được chỉ ra bằng câu lệnh PRINT:

Số tiền rút không thể vượt quá 80000.

Trigger UPDATE

Trigger UPDATE sao chép bản ghi gốc vào bảng Deleted và bản ghi mới vào bảng Inserted khi bản ghi được cập nhật. Sau đó nó đánh giá bản ghi mới để xác định xem các giá trị này có phù hợp với các ràng buộc đã chỉ định trong bảng trigger hay không.

Nếu các giá trị mới là hợp lệ thì bản ghi từ bảng Inserted sẽ được sao chép vào bảng trigger. Tuy nhiên, nếu các giá trị mới là không hợp lệ thì thông báo lỗi được hiển thị. Ngoài ra, bản ghi gốc được sao chép từ bảng Deleted sẽ được đưa trở lại bảng trigger.

Trigger UPDATE được tạo ra bằng cách sử dụng từ khóa UPDATE trong câu lệnh CREATE TRIGGER và ALTER TRIGGER.

Sau đây là cú pháp cho việc tạo ra trigger UPDATE ở mức bảng:

CREATE TRIGGER [schema_name.] trigger_name ON [schema_name.] table_name [WITH ENCRYPTION] {FOR UPDATE} AS
[IF UPDATE (column_name)...]
[{AND | OR} UPDATE (column_name)...]
<sql_statements>

, trong đó:

FOR UPDATE: chỉ ra rằng trigger DML này sẽ được gọi sau các hoạt động cập nhật.

Đoạn mã sau đây tạo ra trigger UPDATE ở mức bảng trên bảng EmployeeDetails. Khi một bản ghi được sửa đổi thì trigger UPDATE được kích hoạt. Nó sẽ kiểm tra xem ngày tháng năm sinh có lớn hơn ngày hôm nay không. Nó sẽ hiển thị thông báo lỗi cho các giá trị không hợp lệ và quay lui hoạt động sửa đổi bằng cách sử dụng câu lệnh ROLLBACK TRANSACTION.

CREATE TRIGGER CheckBirthDate ON EmployeeDetails FOR UPDATE AS
IF (SELECT BirthDate From inserted) > getDate()
BEGIN
PRINT 'Ngày tháng năm sinh không thể lớn hơn ngày hôm nay.'
ROLLBACK
END

Đoạn mã dưới cập nhật một bản ghi trong đó ngày tháng năm sinh không hợp lệ được chỉ định. Điều này làm cho trigger UPDATE hiển thị thông báo lỗi và quay lui giao tác.

UPDATE EmployeeDetails SET BirthDate='2030-12-22' WHERE EmployeeID='E06'

Thông báo lỗi sau được hiển thị như được chỉ ra bằng câu lệnh PRINT:

Ngày tháng năm sinh không thể lớn hơn ngày hôm nay.

Những trigger UPDATE có thể được tạo ra ở mức cột hoặc ở mức bảng. Những trigger ở mức cột thực thi khi các lần cập nhật được thực hiện trong cột chỉ định. Những trigger ở mức bảng thực thi khi các lần cập nhật được thực hiện bất cứ đâu trong toàn bộ bảng. Để tạo ra một trigger UPDATE ở mức cột ta sử dụng hàm UPDATE().

Hàm UPDATE()

Hàm này trả về một giá trị Boolean, nó chỉ ra liệu hành động UPDATE hoặc INSERT đã được thực hiện trên một khung nhìn hoặc cột cụ thể của một bảng hay chưa. Hàm UPDATE () có thể được sử dụng ở bất cứ nơi nào bên trong phần thân của một trigger UPDATE hoặc INSERT.

Sau đây là cú pháp cho hàm UPDATE():

UPDATE(tên_cột)

, trong đó:

tên_cột: là tên của cột để kiểm tra về hành động INSERT hoặc UPDATE.

Đoạn mã sau tạo ra trigger UPDATE có tên Accounting trên bảng Account_Transactions để cập nhật các cột TransactionID hoặc EmployeeID.

CREATE TRIGGER Accounting
ON Account_Transactions
AFTER UPDATE
AS
IF ( UPDATE (TransactionID) OR UPDATE (EmployeeID) )
BEGIN
RAISERROR (50009, 16, 10)
END;
GO

Còn đoạn mã sau sẽ tạo trigger UPDATE có tên Check_EmployeeID ở mức cột trên cột EmployeeID của bảng EmployeeDetails nhằm mục đích ngăn chặn thay đổi giá trị trên cột này. Nếu người dùng tiến hành sửa giá trị trên cột EmployeeID thì trigger UPDATE được kích hoạt và thông báo lỗi được hiển thị.

CREATE TRIGGER Check_EmployeeID ON EmployeeDetails FOR UPDATE AS
IF UPDATE(EmployeeID)
BEGIN
PRINT 'Bạn không thể thay đổi ID của nhân viên'
ROLLBACK TRANSACTION
END

Đoạn mã dưới cập nhật một bản ghi trong đó giá trị trong cột EmployeeID đang được sửa đổi. Điều này làm cho trigger UPDATE được kích hoạt, nó hiển thị thông báo lỗi và quay lui giao tác đó.

UPDATE EmployeeDetails SET EmployeeID='E12' WHERE EmployeeID='E04'

Trigger Delete

Ta có thể tạo ra trigger DELETE để hạn chế người dùng không xoá một bản ghi cụ thể trong bảng. Những điều sau đây sẽ xảy ra nếu người dùng cố gắng xóa bản ghi:

· Bản ghi bị xóa khỏi bảng trigger và chèn vào bảng Deleted

· Kiểm tra các ràng buộc liên quan khi xóa

· Nếu có ràng buộc trên bản ghi để ngăn chặn việc xóa, trigger DELETE sẽ hiển thị thông báo lỗi

· Bản ghi đã xóa được lưu trữ trong bảng Deleted được sao chép ngược lại bảng trigger.

Trigger DELETE được tạo bằng cách sử dụng từ khóa DELETE trong câu lệnh CREATE TRIGGER.

Sau đây là cú pháp cho việc tạo ra một trigger DELETE:

CREATE TRIGGER <trigger_name> ON <table_name> [WITH ENCRYPTION] FOR DELETE AS <sql_statement>

, trong đó:

DELETE: chỉ ra rằng trigger DML này sẽ được gọi bởi các hoạt động xóa.

Đoạn mã sau tạo ra một trigger DELETE trên bảng Account_Transactions. Nếu bản ghi có giá trị 'T01' thuộc một TransactionID bị xóa thì trigger DELETE được kích hoạt và thông báo lỗi được hiển thị.

CREATE TRIGGER CheckTransactions
ON Account_Transactions
FOR DELETE
AS
IF 'T01' IN (SELECT TransactionID FROM deleted)
BEGIN
PRINT 'Không thể xóa bản ghi này.'
ROLLBACK TRANSACTION
END

Đoạn mã dưới thử xóa bản ghi từ bảng Account_Transactions, trong đó mã giao dịch là 'T01'.

DELETE FROM Account_Transactions WHERE TransactionID='T01'

Thông báo lỗi được hiển thị như được chỉ ra bằng câu lệnh PRINT:

Không thể xóa bản ghi này.

Trigger AFTER

Trigger AFTER

Trigger AFTER được thực thi khi hoàn thành các hoạt động INSERT, UPDATE và DELETE. Trigger AFTER chỉ có thể được tạo ra trên các bảng. Bảng có thể có nhiều loại trigger này được định nghĩa cho mỗi hành động. Nếu có nhiều trigger AFTER được tạo ra trên cùng một bảng thì người dùng phải định nghĩa thứ tự thực thi cho các trigger này. Trigger AFTER được thực thi khi kiểm tra ràng buộc trong bảng đã hoàn tất. Ngoài ra, trigger được thực thi sau khi các bảng Inserted và Deleted được tạo ra. Hình dưới đây thể hiện các loại trigger AFTER.

sql: Trigger After

Sau đây là cú pháp cho việc tạo ra trigger AFTER:

CREATE TRIGGER <trigger_name>
ON <table_name>
[WITH ENCRYPTION]
{ FOR | AFTER }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
AS <sql_statement>

, trong đó:

FOR | AFTER: chỉ ra rằng trigger DML thực thi sau khi các hoạt động sửa đổi được hoàn tất.

{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }: chỉ ra những hoạt động gọi trigger.

Đoạn mã sau tạo ra một trigger AFTER DELETE trên bảng EmployeeDetails. Nếu có bất kỳ bản ghi nhân viên nào bị xóa khỏi bảng thì trigger AFTER DELETE sẽ được kích hoạt. Trigger sẽ hiển thị số lượng bản ghi nhân viên đã xóa khỏi bảng này.

CREATE TRIGGER Employee_Deletion
ON EmployeeDetails
AFTER DELETE
AS
BEGIN
DECLARE @num nchar;
SELECT @num = COUNT(*) FROM deleted
PRINT N'Số lượng nhân viên đã xóa = ' + @num
END

Đoạn mã dưới đây sẽ xóa một bản ghi khỏi bảng EmployeeDetails.

DELETE FROM EmployeeDetails WHERE EmployeeID='E07'

Thông báo lỗi sau được hiển thị:

Số lượng nhân viên đã xóa = 0

Trigger INSTEAD OF

Trigger INSTEAD OF được thực thi thay thế cho các hoạt động INSERT, UPDATE hoặc DELETE. Các trigger INSTEAD OF có thể được tạo ra trên các bảng cũng như khung nhìn. Mỗi bảng hay khung nhìn chỉ có thể có một trigger INSTEAD OF được định nghĩa cho mỗi hoạt động INSERT, UPDATE và DELETE.

Các trigger INSTEAD OF được thực thi trước khi các lần kiểm tra ràng buộc được thực hiện trên bảng. Những trigger này được thực thi sau khi tạo ra các bảng Inserted và Deleted. Các trigger INSTEAD OF tăng sự đa dạng của các loại cập nhật mà người dùng có thể thực hiện đối với khung nhìn. Hình sau thể hiện ví dụ về hoạt động của trigger INSTEAD OF.

SQL: Trigger Instead of
Hoạt động của trigger INSTEAD OF

Trong ví dụ được trình bày trong hình trên, trigger INSTEAD OF DELETE trên bảng Account_Types được tạo ra. Nếu có bất kỳ bản ghi nào trong bảng Account_Types bị xóa thì những bản ghi tương ứng trong bảng Customer_Details cũng sẽ được gỡ bỏ. Do đó, thay vì làm việc chỉ trên một bảng, thì ở đây trigger đảm bảo rằng hoạt động xóa được thực hiện trên cả hai bảng.

Lưu ý: Người dùng không thể tạo các trigger INSTEAD OF cho các hoạt động xóa hoặc cập nhật trên các bảng có các tùy chọn tầng ON DELETE và tầng ON UPDATE đã chọn.

Sau đây là cú pháp cho việc tạo ra trigger INSTEAD OF:

CREATE TRIGGER <trigger_name>
ON { <table_name> | <view_name> }
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
AS <sql_statement>

, trong đó:
view_name: chỉ ra khung nhìn mà trên đó trigger DML được tạo ra.

INSTEAD OF: chỉ ra rằng trigger DML thực thi thay cho các hoạt động sửa đổi. Những trigger không được định nghĩa trên các khung nhìn có thể cập nhật sử dụng WITH CHECK OPTION.

Đoạn mã sau đây tạo ra trigger INSTEAD OF DELETE trên bảng Account_Transactions. Nếu có bất kỳ bản ghi nào trong bảng này bị xóa, thì những bản ghi tương ứng trong bảng EmployeeDetails cũng sẽ được gỡ bỏ.

CREATE TRIGGER Delete_AccType
ON Account_Transactions
INSTEAD OF DELETE
AS
BEGIN
DELETE FROM EmployeeDetails WHERE EmployeeID IN
(SELECT TransactionTypeID FROM deleted)
DELETE FROM Account_Transactions WHERE TransactionTypeID IN
(SELECT TransactionTypeID FROM deleted)
END

Sử dụng trigger INSTEAD OF với các khung nhìn

Các trigger INSTEAD OF có thể được chỉ ra trên các bảng cũng như khung nhìn. Trigger được thực thi thay vì hành động kích hoạt ban đầu. Các trigger INSTEAD OF cung cấp phạm vi rộng hơn và các loại cập nhật mà người dùng có thể thực hiện đối với khung nhìn. Mỗi bảng hoặc khung nhìn được giới hạn chỉ cho một trigger INSTEAD OF cho mỗi hành động kích hoạt (INSERT, UPDATE hoặc DELETE).

Người dùng không thể tạo ra một trigger INSTEAD OF trên các khung nhìn có mệnh đề WITH CHECK OPTION đã định nghĩa.

Hình dưới đây hiển thị ví dụ về việc sử dụng các trigger INSTEAD OF với các khung nhìn.

Đoạn mã sau tạo ra một bảng có tên là Employee_Personal_Details.

CREATE TABLE Employee_Personal_Details (
EmpID int NOT NULL,
FirstName varchar(30) NOT NULL,
LastName varchar(30) NOT NULL,
Address varchar(30)
)

Đoạn mã sau tạo ra một bảng có tên là Employee_Salary_Details.

CREATE TABLE Employee_Salary_Details (
EmpID int NOT NULL,
Designation varchar(30),
Salary int NOT NULL
)

Đoạn mã dưới đây tạo ra một khung nhìn Employee_Details_View sử dụng các cột từ hai bảng trên bằng cách nối hai bảng theo cột chung EmpID.

CREATE VIEW Employee_Details_View
AS
SELECT e1.EmpID, FirstName, LastName, Designation, Salary
FROM Employee_Personal_Details e1
JOIN Employee_Salary_Details e2
ON e1.EmpID = e2.EmpID

Đoạn mã sau tạo ra trigger INSTEAD OF DELETE có tên Delete_Employees trên khung nhìn Employee_Details_View ở trên. Khi một hàng được xóa khỏi khung nhìn thì trigger sẽ được kích hoạt, và nó sẽ xóa những bản ghi tương ứng khỏi những bảng cơ sở của khung nhìn có tên là Employee_Personal_Details và Employee_Salary_Details.

CREATE TRIGGER Delete_Employees
ON Employee_Details_View
INSTEAD OF DELETE
AS
BEGIN
DELETE FROM Employee_Salary_Details WHERE EmpID IN
(SELECT EmpID FROM deleted)
DELETE FROM Employee_Personal_Details WHERE EmpID IN
(SELECT EmpID FROM deleted)

Đoạn mã dưới đây xóa một hàng khỏi khung nhìn Employee_Details_View trong đó EmpID='3'.

DELETE FROM Employee_Details _View WHERE EmpID='3'

Solution Practical 2

--Lab 2--
create database DBLab2;
use DBLab2;
 
--Tạo các bảng
create table Student(
       RN int not null ,
       Name nvarchar(20),
       Age tinyint,
       constraint pk1 primary key(RN),
);
create table Test(
       TestID int not null,
       Name varchar(20),
       constraint pk2 primary key(TestID),
);
create table StudentTest(
       RN int,
       TestID int,
       [Date] date,
       Mark float,
       constraint fk1 foreign key(RN) references Student(RN),
       constraint fk2 foreign key(TestID) references Test(TestID),
);
 
--Chèn dữ liệu
insert Student values (1,'Nguyen Hong Ha',20), (2,'Truong Ngoc Anh',30), (3,'Tuan Minh',25), (4,'Dan Truong',22);
insert Test values (1,'EPC'), (2,'DWMX'), (3,'SQL1'), (4,'SQL2');
 
insert StudentTest values
       (1,1,'7/17/2006',8),
       (1,2,'7/18/2006',5),
       (1,3,'7/19/2006',7),
       (2,1,'7/17/2006',7),
       (2,2,'7/18/2006',4),
       (2,3,'7/19/2006',2),
       (3,1,'7/17/2006',10),
       (3,3,'7/18/2006',1);
 
--Hiển thị
--a
select RN, convert(numeric(4,2),Mark) from StudentTest;
 
--b
select * from Student where Age>25;
 
--c
select * from Student where Age in (20,30);
 
--d
select * from Test where Name like'%[s]%';
 
--e
select * from StudentTest where Mark>5;
 
--f
select * from Student where Name like N'% ____';
 
--g
select * from Student where name like N'______ %';
 
--h
select * from Student where name like N'[^r][^r][^r][^r][^r][^r] %';
 
--i
select * from Student where RN not in(select RN from StudentTest);
 
--k
alter table Student add [Status] varchar(10) default('Young');
 
--Xóa ràng buộc khóa ngoại
--l
alter table StudentTest drop constraint fk1,fk2 ;
 
--m
alter table Student drop constraint pk1;
alter table Test drop constraint pk2 ;
 
--Xóa các bảng
--n
drop table Student;
drop table StudentTest, Test;
 
--Xóa database
--o
use master;
drop database DBLab2;
------------------------------------------------------------------------------
--Extra
--Chạy lại các câu lệnh tạo databse, table, tạo các ràng buộc và nhập liệu.
 
--1
select avg(Age) from Student;
 
--2
select top(1)*from Student order by Age DESC;
 
--3
select top(1)*from Student order by Age ASC;
 
--4
select top(1) Name,Mark from StudentTest a join Test b on a.TestID=b.TestID order by Mark DESC;
 
--5
select top(1) Name,Mark from StudentTest a join Test b on a.TestID=b.TestID order by Mark ASC;
 
--6
select top(1) with ties Name,[Date] from Student a join StudentTest b on a.RN=b.RN order by [Date] DESC;
 
--7
select top(1) with ties Name,[Date] from Student a join StudentTest b on a.RN=b.RN order by [Date] ASC;
 
--8
select sum(Age) from Student;
 
--9
select Name,[Date],DATEDIFF(DD,date,GetDate()) AS [cach day/ngay] from StudentTest a join Test b on a.TestID=b.TestID ;
 
--10
select top(1) with ties Name,Mark from Student a join StudentTest b on a.RN=b.RN order by Mark DESC;
 
--11
select top(1) with ties Name,Mark from Student a join StudentTest b on a.RN=b.RN order by Mark ASC;
 
--12
select Name,convert(numeric(4,2),avg(Mark)) as [Diem TB] from Student a full join StudentTest b on a.RN=b.RN group by Name order by avg(Mark) DESC;
 
--13
select a.Name as [Hoc vien],c.Name as [Mon hoc] from Student a join StudentTest b on a.RN=b.RN join Test c on b.TestID=c.TestID ;
 
--14
select * from Student where RN not in(select RN from StudentTest);
 
--15
select a.Name as [Hv thi lai], c.Name as [Mon thi lai] from Student a join StudentTest b on a.RN=b.RN join Test c on b.TestID=c.TestID where Mark<5;
 
--16
select top(1) Name,convert(numeric(4,2),avg(Mark)) as [Diem TB] from Student a full join StudentTest b on a.RN=b.RN group by Name order by avg(Mark) DESC;
 
--17
select top(1) Name,convert(numeric(4,2),avg(Mark)) as [Diem TB] from Student a join StudentTest b on a.RN=b.RN group by Name order by avg(Mark) ASC;
 
--18
select Name, MAX(Mark) as [diem cao nhat]   from Test a full join StudentTest b on a.TestID=b.TestID group by Name ;
 
--19

select a.Name as [Hoc vien],c.Name as [Mon hoc] from Student a left join StudentTest b on a.RN=b.RN left join Test c on b.TestID=c.TestID ;


Câu 13 và 19 bài Lab2 (cách #):

------ Câu 13-----
select [Hoc vien], Stuff( (SELECT ', ' + [M.hoc] 
FROM (select a.Name as [H.vien],c.Name as [M.hoc] from Student a join StudentTest b on a.RN=b.RN join Test c on b.TestID=c.TestID) as tg2 
WHERE tg2.[H.vien] = [Hoc vien] 
FOR XML PATH ('')),1,2,'') AS [cac Mon hoc]
 

from (select a.Name as [Hoc vien],c.Name as [Mon hoc] from Student a join StudentTest b on a.RN=b.RN left join Test c on b.TestID=c.TestID) as tg

group by [Hoc vien]; 

------Câu 19------
select [Hoc vien],
Stuff( (SELECT ', ' + [M.hoc] 
FROM (select a.Name as [H.vien],c.Name as [M.hoc] from Student a full join StudentTest b on a.RN=b.RN join Test c on b.TestID=c.TestID) as tg2 
WHERE tg2.[H.vien] = [Hoc vien] 
FOR XML PATH ('')),1,2,'') AS [cac Mon hoc]

from (select a.Name as [Hoc vien],c.Name as [Mon hoc] from Student a full join StudentTest b on a.RN=b.RN left join Test c on b.TestID=c.TestID) as tg

group by [Hoc vien];

Làm việc với trigger DML và DDL

Làm việc với trigger DML

SQL Server cho phép người dùng tạo ra nhiều trigger AFTER cho mỗi hành động kích hoạt (như là UPDATE, INSERT và DELETE) trên một bảng. Tuy nhiên, người dùng chỉ có thể tạo ra một trigger INSTEAD OF cho mỗi hành động kích hoạt trên một bảng.

Khi người dùng có nhiều trigger AFTER trên một hành động kích hoạt thì tất cả những trigger này phải có tên khác nhau. Trigger AFTER có thể bao gồm một số câu lệnh SQL thực hiện các hàm khác nhau.

Sơ đồ dưới đây thể hiện các loại trigger DML:

sql: các loại trigger dml
Các loại trigger DML

Lưu ý: Một trigger AFTER đơn lẻ có thể được gọi bởi nhiều hơn một hành động kích hoạt.

Thứ tự thực thi các trigger DML

SQL Server cho phép người dùng chỉ ra trigger AFTER nào sẽ được thực thi đầu tiên và cuối cùng. Tất cả các trigger AFTER đã gọi giữa những trigger đầu tiên và cuối cùng không có thứ tự thực thi nhất định.

Tất cả các hành động gây ra thì đều có trigger đầu tiên và cuối cùng được định nghĩa cho chúng. Tuy nhiên, không có hai hành động kích hoạt trên một bảng có thể có cùng các trigger đầu tiên và cuối cùng.

Người dùng có thể sử dụng thủ tục lưu trữ sp_settriggerorder để định nghĩa thứ tự của các trigger DML AFTER. Hình dưới đây hiển thị thứ tự thực thi của các trigger DML.

sql: thứ tự thực thi trigger

Sau đây là cú pháp để chỉ ra thứ tự thực thi nhiều trigger DML AFTER:

sp_settriggerorder [ @triggername = ] '[ triggerschema. ] triggername'
, [ @order = ] 'value'
, [ @stmttype = ] 'statement_type'

, trong đó:

[ triggerschema.] triggername: là tên của trigger DML hoặc DDL và lược đồ của nó và thứ tự của nó cần phải được chỉ ra.

value: chỉ ra thứ tự thực hiện của trigger như FIRST, LAST, hoặc NONE. Nếu FIRST được chỉ ra thì trigger được kích hoạt trước tiên. Còn nếu LAST được chỉ ra thì trigger được kích hoạt cuối cùng. Nếu NONE được chỉ ra thì thứ tự kích hoạt của trigger là không xác định.

statement_type: chỉ ra loại câu lệnh SQL (INSERT, UPDATE hoặc DELETE) gọi trigger DML.

Ở đoạn mã dưới đây thì trước tiên thực thi trigger Employee_Deletion được định nghĩa trên bảng khi hành động DELETE được thực hiện trên cột Withdrawal.

EXEC sp_settriggerorder @triggername = 'Employee_Deletion ', @order = 'FIRST', @stmttype = 'DELETE'

Xem định nghĩa trigger DML

Định nghĩa trigger bao gồm tên trigger, bảng trên đó trigger được tạo ra, các hành động kích hoạt và các câu lệnh SQL được thực thi. SQL Server cung cấp thủ tục lưu trữ sp_helptext để xem các định nghĩa trigger.

Tên trigger DML phải được chỉ ra như là tham số khi thực thi sp_helptext.

Lưu ý: Không thể xem định nghĩa trigger nếu định nghĩa được mã hóa.

Sau đây là cú pháp cho việc xem trigger DML:

sp_helptext '<DML_trigger_name>'

, trong đó:

DML_trigger_name: chỉ ra tên của trigger DML định nghĩa của nó sẽ được hiển thị.

Đoạn mã dưới đây hiển thị định nghĩa của trigger Employee_Deletion đã tạo ra trên bảng tương ứng.

sp_helptext 'Employee_Deletion'

Sửa trigger DML

Các tham số của trigger được định nghĩa ngay lúc tạo ra trigger. Những tham số này bao gồm loại hành động kích hoạt để gọi trigger và các câu lệnh SQL được thực thi.

Nếu người dùng muốn sửa đổi bất kỳ tham số nào cho trigger DML thì có thể thực hiện theo một trong hai cách sau:

· Xóa bỏ và tạo lại trigger với những tham số mới.

· Thay đổi các tham số bằng cách sử dụng câu lệnh ALTER TRIGGER.

Nếu đối tượng tham chiếu trigger DML được đổi tên thì trigger phải được sửa đổi để phản ánh sự thay đổi trong tên đối tượng.

Lưu ý: Trigger DML có thể được mã hóa để ẩn định nghĩa của nó.

sql: cách sửa trigger dml
Cách sửa các Trigger DML

Sau đây là cú pháp cho việc sửa đổi trigger DML:

ALTER TRIGGER <trigger_name>
ON { <table_name> | <view_name> }
[WITH ENCRYPTION]
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
AS <sql_statement>

, trong đó:

WITH ENCRYPTION: chỉ ra rằng các định nghĩa trigger DML không được hiển thị.

FOR | AFTER: chỉ ra rằng trigger DML thực thi sau khi các hoạt động sửa đổi được hoàn tất.

INSTEAD OF: chỉ ra rằng trigger DML thực thi thay cho các hoạt động sửa đổi.

Đoạn mã sau đây thay đổi trigger CheckEmployeeID đã tạo ra trên bảng EmployeeDetails bằng cách sử dụng tùy chọn WITH ENCRYPTION.

ALTER TRIGGER CheckEmployeeID
ON EmployeeDetails
WITH ENCRYPTION
FOR INSERT
AS
IF 'E01' IN (SELECT EmployeeID FROM inserted)
BEGIN
PRINT 'Người dùng không thể chèn vào các khách hàng của Áo'
ROLLBACK TRANSACTION
END

Bây giờ, nếu người dùng cố gắng xem định nghĩa của trigger CheckEmployeeID bằng cách sử dụng thủ tục lưu trữ sp_helptext, thông báo lỗi sau đây được hiển thị:

The text for object CheckEmployeeID is encrypted

Xóa trigger DML

SQL Server cung cấp tùy chọn xóa bỏ một trigger DML đã tạo ra trên bảng nếu nó không còn cần thiết nữa. Ta có thể xóa trigger bằng cách sử dụng câu lệnh DROP TRIGGER. Cũng có thể xóa bỏ nhiều trigger bằng cách sử dụng một câu lệnh trigger xóa bỏ đơn lẻ.

Khi một bảng bị xóa bỏ thì tất cả các trigger đã định nghĩa trên bảng đó cũng được xóa bỏ.

Lưu ý: Khi trigger DML bị xóa bỏ khỏi bảng thì thông tin về trigger cũng bị loại bỏ khỏi các khung nhìn.

Sau đây là cú pháp cho việc xóa bỏ các trigger DML:

DROP TRIGGER <DML_trigger_name> [ ,...n ]

, trong đó:

DML_trigger_name: chỉ ra tên của trigger DML sẽ được xóa bỏ.

[ ,...n ]: chỉ ra rằng nhiều trigger DML có thể được xóa bỏ.

Đoạn mã sau minh họa việc xóa bỏ trigger CheckEmployeeID đã tạo ra trên bảng EmployeeDetails:

DROP TRIGGER CheckEmployeeID;

Làm việc với trigger DDL

Trigger Ngôn ngữ Định nghĩa Dữ liệu (DDL) thực thi thủ tục lưu trữ khi các sự kiện DDL như là các câu lệnh CREATE, ALTER và DROP xảy ra trong cơ sở dữ liệu hoặc máy chủ. Các trigger DDL chỉ có thể hoạt động khi hoàn thành các sự kiện DDL.

Có thể sử dụng các trigger DDL để ngăn chặn những thay đổi trong lược đồ cơ sở dữ liệu. Lược đồ là một tập hợp các đối tượng như bảng, dạng xem, và vân vân trong một cơ sở dữ liệu.

Các trigger DDL có thể gọi một sự kiện hoặc hiển thị một thông báo dựa trên những sửa đổi đã thử trên lược đồ này. Các trigger DDL được định nghĩa ở mức cơ sở dữ liệu hoặc ở mức máy chủ.

Sơ đồ dưới đây thể hiện các loại trigger DDL:

sql: các trigger ddl
Các trigger DDL

Sau đây là cú pháp tạo trigger DDL:

CREATE TRIGGER <trigger_name>
ON { ALL SERVER | DATABASE }
[WITH ENCRYPTION]
{ FOR | AFTER } { <event_type> }
AS <sql_statement>

, trong đó:

ALL SERVER: chỉ ra rằng trigger DDL được thực thi khi các sự kiện DDL xảy ra trong máy chủ hiện tại.

DATABASE: chỉ ra rằng trigger DDL được thực thi khi các sự kiện DDL xảy ra trong cơ sở dữ liệu hiện tại.

event_type: chỉ ra tên của sự kiện DDL để gọi trigger DDL.

Đoạn mã sau tạo ra một trigger DDL để xóa bỏ và thay đổi một bảng:

CREATE TRIGGER Secure
ON DATABASE
FOR DROP_TABLE, ALTER_TABLE
AS
PRINT 'Bạn phải vô hiệu hóa trigger "Secure" để xóa bỏ hoặc sửa các bảng!'
ROLLBACK TRAN;

Trong đoạn mã này, trigger DDL được tạo ra ứng với các câu lệnh DROP TABLE và ALTER TABLE. 

Phạm vi của trigger DDL

Các trigger DDL được gọi bằng các câu lệnh SQL đã thực thi trong cơ sở dữ liệu hiện tại hoặc trên máy chủ hiện tại. Ví dụ, trigger DDL đã tạo ra cho câu lệnh CREATE TABLE thì thực thi trên sự kiện CREATE TABLE trong cơ sở dữ liệu. Trigger DDL đã tạo ra cho câu lệnh CREATE LOGIN thực thi trên sự kiện CREATE LOGIN trong máy chủ.

Phạm vi của trigger DDL phụ thuộc vào việc trigger thực thi cho các sự kiện cơ sở dữ liệu hay các sự kiện máy chủ. Theo đó, các trigger DDL được phân thành hai loại như sau:

Các trigger DDL có phạm vi cơ sở dữ liệu:

Các trigger DDL loại này được gọi bằng những sự kiện thay đổi lược đồ cơ sở dữ liệu. Những trigger này được lưu trữ trong cơ sở dữ liệu và thực thi trên các sự kiện DDL, ngoại trừ những vấn đề liên quan đến các bảng tạm thời.

Các trigger DDL có phạm vi máy chủ

Các trigger DDL loại này được gọi bằng các sự kiện DDL ở mức máy chủ. Những trigger này được lưu trữ trong cơ sở dữ liệu master.

Sơ đồ dưới đây thể hiện phạm vi của các trigger DDL:

sql: các phạm vi của trigger ddl
Phạm vi của các trigger DDL

Trigger lồng

Cả trigger DDL và DML được lồng nhau khi trigger thực hiện một hành động kích hoạt trigger khác. Ta có thể lồng các trigger DDL và DML lên đến 32 mức. Giả sử nếu một trigger sửa đổi một bảng trên đó có một trigger khác, thì trigger thứ hai được kích hoạt, rồi sau đó gọi một trigger thứ ba, và vân vân.

Nếu các trigger lồng nhau được cho phép, khi đó những trigger này theo thứ tự bắt đầu một vòng lặp vô hạn. Điều này sẽ dẫn đến vượt quá số mức lồng nhau giới hạn và trigger sẽ chấm dứt.

Các trigger lồng nhau có thể được sử dụng để thực hiện các hàm như lưu trữ bản sao lưu của những hàng bị ảnh hưởng bằng những hành động trước đó.

Trigger Transact-SQL thực thi mã có quản thông qua tham chiếu CLR, tổng hợp, hoặc loại, tham chiếu số đếm làm một mức đối với giới hạn xếp lồng 32 cấp. Các phương pháp được gọi từ bên trong mã có quản không được đếm đối với giới hạn này.

Người dùng có thể vô hiệu hóa các trigger lồng nhau, bằng cách đặt tùy chọn trigger lồng nhau của thủ tục lưu trữ sp_configure thành 0 hoặc off, sau đó cấu hình mặc định được cho phép cho các trigger lồng nhau. Nếu tùy chọn trigger lồng nhau là off, khi đó trigger đệ quy bị vô hiệu hóa, không phân biệt thiết lập trigger đệ quy được đặt bằng cách sử dụng ALTER DATABASE.

Đoạn mã sau tạo ra một trigger AFTER DELETE có tên là Employee_Deletion trên bảng Employee_Personal_Details:

CREATE TRIGGER Employee_Deletion
ON Employee_Personal_Details
AFTER DELETE
AS
BEGIN
PRINT 'Việc xóa sẽ ảnh hưởng đến bảng Employee_Salary_Details'
DELETE FROM Employee_Salary_Details WHERE EmpID IN
(SELECT EmpID FROM deleted)
END

Khi một bản ghi được xóa khỏi bảng Employee_Personal_Details, trigger Employee_Deletion được kích hoạt và thông báo được hiển thị. Ngoài ra, bản ghi của nhân viên cũng được xóa khỏi bảng Employee_Salary_Details.

Đoạn mã sau tạo ra một trigger AFTER DELETE có tên Deletion_Confirmation trên bảng Employee_Salary_Details:

CREATE TRIGGER Deletion_Confirmation
ON Employee_Salary_Details
AFTER DELETE
AS
BEGIN
PRINT 'Chi tiết nhân viên đã xóa thành công khỏi bảng Employee_Salary_Details'
END
DELETE FROM Employee_Personal_Details WHERE EmpID=1

Khi bản ghi được xóa khỏi bảng Employee_Salary_Details thì trigger Deletion_Confirmation được kích hoạt. Trigger này in thông báo xác nhận bản ghi đang bị xóa. Như vậy, các trigger Employee_Deletion và Deletion_Confirmation là lồng nhau.

Xử lý nhiều hàng trong một phiên

Khi người dùng viết mã lệnh cho một trigger DML thì mã lệnh này là câu lệnh đơn lẻ. Câu lệnh đơn lẻ này sẽ ảnh hưởng đến nhiều hàng dữ liệu thay vì một hàng đơn lẻ. Đây là một hành vi phổ biến cho các trigger DELETE và UPDATE bởi những câu lệnh này thường ảnh hưởng đến nhiều hàng. Hành vi cho các trigger INSERT ít phổ biến hơn bởi câu lệnh INSERT cơ bản chỉ thêm một hàng.

Khi chức năng của một trigger DML tự động kéo theo việc tính toán lại các giá trị của một bảng và lưu trữ kết quả vào bảng khác, thì việc cân nhắc trên nhiều hàng là rất quan trọng.

Đoạn mã sau lưu trữ tổng đang chạy cho một lần chèn đơn hàng:

CREATE TRIGGER PODetails
ON Purchasing.PurchaseOrderDetail
AFTER INSERT AS
UPDATE PurchaseOrderHeader
SET SubTotal = SubTotal + LineTotal
FROM inserted
WHERE PurchaseOrderHeader.PurchaseOrderID = inserted.PurchaseOrderID;

Trong đoạn mã này, tổng phụ được tính toán và lưu trữ cho một hoạt động chèn đơn hàng.

Đoạn mã dưới đây lưu trữ tổng đang chạy cho một lần chèn đa hàng hoặc đơn hàng:

CREATE TRIGGER PODetailsMultiple
ON Purchasing.PurchaseOrderDetail
AFTER INSERT AS
UPDATE Purchasing.PurchaseOrderHeader
SET SubTotal = SubTotal +
(SELECT SUM(LineTotal)
FROM inserted
WHERE PurchaseOrderHeader.PurchaseOrderID
= inserted.PurchaseOrderID)
WHERE PurchaseOrderHeader.PurchaseOrderID IN
(SELECT PurchaseOrderID FROM inserted);

Trong đoạn mã này, tổng phụ được tính toán và lưu trữ cho hoạt động chèn đa hàng hoặc đơn hàng.

Ảnh hưởng hiệu suất của các trigger

Trong thực tế, trigger không hao tốn chi phí, hơn nữa chúng lại hoạt động khá tốt và nhạy. Tuy nhiên, nhiều vấn đề về hiệu suất có thể xảy ra do logic hiện tại bên trong trigger. Giả sử một trigger tạo ra một con trỏ và lặp qua nhiều hàng, thì sẽ có một sự suy giảm khá lớn về hiệu suất và tốc độ thực hiện các câu lệnh trong quá trình này.

Tương tự như vậy, nếu trigger thực thi các câu lệnh SQL khác nhau đối với các bảng khác nhau tách biệt khỏi các bảng Inserted và Deleted, thì điều này một lần nữa sẽ dẫn đến sự suy giảm tốc độ của các câu lệnh SQL nằm trong trigger này.

Một nguyên tắc tốt sẽ giúp có logic đơn giản trong các trigger và tránh được việc phải sử dụng các con trỏ trong khi thực thi các câu lệnh đối với bảng khác và các tác vụ khác làm cho hiệu suất giảm.

Solution Practical 3

create database DBLab3 ;
use DBLab3 ;

--tao bang
create table Customer(
    cID int not null,
    cName varchar(25),
    cAge tinyint,
    cGender  bit,
);
create table [Order](
    oID int not null,
    cID int ,
    oDate date,
);
create table product(
    pID int not null,
    pName varchar(25),
    pPrice int,
);
create table OrderDetail(
    oID int,
    pID int,
    odQTY int,
);

--tao khoa chinh
alter table Customer add constraint pk1 primary key(cID);
alter table [Order] add constraint pk2 primary key(oID);
alter table Product add constraint pk3 primary key(pID);

-- tao khoa ngoai
alter table [Order] add constraint fk1 foreign key (cID) references Customer(cID);
alter table OrderDetail add constraint fk2 foreign key (oID) references [Order](oID);
alter table OrderDetail add constraint fk3 foreign key (pID) references Product(pID);

--nhap du lieu
insert Customer values (1,'Elisha Cuthbert', 26,0),
                        (2,'Cristiano Ronaldo',23,1),
                        (3,'Gemma Atkinson',24,0),
                        (4,'Maria Sharapova',22,null);

insert product values (1,'Washing Machine',3),
                        (2,'Fridge',5),
                        (3,'Air Conditioner',7),
                        (4,'Electric Fan',1),
                        (5,'Electric Cooker',2);

insert [Order] values (1,1,'3/21/2008'),
                        (2,2,'3/23/2008'),
                        (3,1,'3/16/2008'); 

insert OrderDetail values (1,1,3), (1,3,7), (1,4,2), (2,1,1), (3,1,8), (2,5,4), (2,3,3);

-------Truy van---------------

--4
select *from [Order] order by oDate;

--5
select cName,substring(cName,CHARINDEX(' ',cName),2) as[chu cai dau cua ten] from Customer; 

--6
select top(1) with ties pPrice from product order by pPrice DESC;

--7
select top(1) with ties pPrice from product order by pPrice;

--8
select 'Price of '+pName+' is '+convert(char(3),pPrice) from product;

--9
select top(3) pName,pPrice into    Top3Product from product order by pPrice DESC;
select *from Top3Product;

--10
select * from Customer where cName like '_______________';

--11
select * from product where pName like '%Electric%';

--12
select GETDATE() as [Ngay hien tai], DATEADD(MI,5000,GETDATE());

--13
alter table [Oder] drop constraint fk1;
alter table OrderDetail drop constraint fk2,fk3;

--14 
alter table Customer drop constraint pk1;
alter table [Order] drop constraint pk2;
alter table product drop constraint pk2;

--15
drop table Customer,[Order],product,OrderDetail,Top3Product;

--16
use master;
drop database DBLab3;

Solution Practical 4

--2.
create database DBLab4;
use DBLab4;

--3. tao bang
create table Customer(
    MaKhach int not null,
    Ten nvarchar(30),
    Sodienthoai varchar(15),
);

create table Item(
    MaHang int not null,
    Ten nvarchar(30),
    Soluong int,
    DonGia float,
);
 create table CustomerItem(
    MaKhach int not null,
    Mahang int not null,
    SoLuongMua int, 
 );

-- tao khoa 
alter table Customer add constraint pk1 primary key(MaKhach);

alter table Item add constraint pk2 primary key(MaHang);

alter table CustomerItem add constraint pk3 primary key (MaKhach,Mahang);

alter table CustomerItem add constraint fk1 foreign key (MaKhach) references Customer(MaKhach);

alter table CustomerItem add constraint fk2 foreign key (MaHang) references Item(Mahang);

--4. Nhap du lieu
insert Item values (1,'Tu Lanh',5,3500), (2,'Ti vi',2,3000), (3,'Dieu hoa',1,8000),
                    (4,'Quat da',5,1700), (5,'May giat',3,5000);

insert Customer values (1,'Dinh Truong Son','1234567'),
                        (2,'Mai Thanh Minh','1357999'),
                        (3,'Nguyen Hong Ha','2468888'); 

insert CustomerItem values (1,1,4), (1,5,1), (2,2,1), (3,3,1), (3,1,1);

------------------Hien thi----------------------------
--6.
select sum(DonGia*SoLuongMua) as [tong thu] from Item a join CustomerItem b on a.MaHang=b.Mahang; 

--7.
select top(1) c.Ten,sum(a.DonGia*b.SoLuongMua) as [TongTien] from Item a join CustomerItem b on a.MaHang=b.Mahang join Customer c on b.MaKhach=c.MaKhach group by c.Ten order by [TongTien] Desc;

--8.
select [Kiem tra] = case COUNT(a.Ten)
    when 0 then 'Khong mua' else 'Co mua' end 
    from Item a join CustomerItem b on a.MaHang=b.Mahang join Customer c on b.MaKhach=c.MaKhach where c.Sodienthoai='2468888' and a.Ten='Tu lanh';

--9.
select a.Ten,isnull((a.Soluong - b.[Tong Mua]),a.Soluong) as [Hang ton],a.DonGia,(isnull((a.Soluong - b.[Tong Mua]),a.Soluong)*a.DonGia) 
from Item a left join (select Mahang,sum(SoLuongMua) as [Tong Mua] from CustomerItem group by Mahang) b on a.MaHang=b.Mahang ;

select sum(a.Soluong)-sum([Tong Mua]) as [HangTonKho],sum(a.DonGia*a.Soluong)-sum(a.DonGia*[Tong Mua]) as [TienTonKho] from Item a left join (select Mahang,sum(SoLuongMua) as [Tong Mua] from CustomerItem group by Mahang) b on a.MaHang=b.Mahang ;

--10.
select top(3) Ten,[Tong Mua] from Item a join (select Mahang,sum(SoLuongMua) as [Tong Mua] from CustomerItem group by Mahang) b on a.MaHang=b.Mahang order by [Tong Mua] DESC;

--11
select Ten as [Chua ban dc] from Item where MaHang not in (select MaHang from CustomerItem);

--12.
select Ten,count(DISTINCT MaHang) as [Loai Hang Mua] from Customer a join CustomerItem b on a.MaKhach=b.MaKhach group by a.Ten having count(MaHang)>1 ; 

--13.
select Ten as [Mua nhieu] from Customer a join (select MaKhach,sum(SoLuongMua) as [Tong Mua] from CustomerItem group by MaKhach) b on a.MaKhach=b.MaKhach where [Tong Mua]>1;

--14.
select c.Ten,sum(b.SoLuongMua*a.DonGia) as [TongTienMua],[Level] = case 
    when sum(b.SoLuongMua*a.DonGia) <5000 then 'Level 1'
    when sum(b.SoLuongMua*a.DonGia) >=5000 and sum(b.SoLuongMua*a.DonGia) <10000 then 'Level 2'
    when sum(b.SoLuongMua*a.DonGia) >=10000 then 'V.I.P'
    else 'Unknow' end
    from Item a join CustomerItem b on a.MaHang=b.Mahang join Customer c on b.MaKhach=c.MaKhach
    group by c.Ten;

Solution Practical 4 - MySQL

#6.
SELECT SUM(donGia*soLuongMua) AS 'Tổng số tiền thu được' FROM items a JOIN customeritem b ON a.maHang=b.maHang

#7.
SELECT a.ten,SUM(donGia*soLuongMua) AS'Tổng số tiền đã mua' FROM customers a JOIN customeritem b ON a.maKhach=b.maKhach JOIN items c ON b.maHang=c.maHang GROUP BY a.maKhach,a.ten HAVING(SUM(donGia*soLuongMua)=(SELECT SUM(donGia*soLuongMua) FROM items d JOIN customeritem e ON d.maHang=e.maHang GROUP BY maKhach ORDER BY SUM(donGia*soLuongMua) DESC LIMIT 1))

 
#8.
SELECT CASE COUNT(*)
 WHEN 0 THEN 'Không mua'
    ELSE 'Có mua'
    END AS 'Kết quả'
FROM customers a JOIN customeritem b ON a.maKhach=b.maKhach JOIN items c ON b.maHang=c.maHang WHERE soDienThoai='2468888' AND c.ten='Tu lanh'
 
#9.
SELECT 
(SELECT ((SELECT SUM(soLuong) FROM items) - (SELECT SUM(soLuongMua) FROM customeritem)))  as 'Tổng số hàng tồn',
(SELECT ((SELECT SUM(donGia*soLuong) from items)-(SELECT SUM(donGia*soLuongMua) FROM items a JOIN customeritem b ON a.maHang=b.maHang))) AS 'Tổng số tiền tồn'
 
#10.
SELECT ten,SUM(soLuongMua) FROM items a JOIN customeritem b ON a.maHang=b.maHang GROUP BY a.maHang,ten ORDER BY SUM(soLuongMua) DESC LIMIT 3
 
#11.
SELECT ten AS 'Những mặt hàng chưa bán được' FROM items WHERE maHang NOT IN(SELECT DISTINCT maHang FROM customeritem)
 
#12.
SELECT ten,COUNT(a.maKhach) AS 'Số loại mặt hàng đã mua' FROM customers a JOIN customeritem b ON a.maKhach=b.maKhach GROUP BY a.maKhach,ten HAVING(COUNT(a.maKhach)>1)
 
#13.
SELECT a.ten AS 'Tên người mua',c.ten AS 'Tên mặt hàng',soLuongMua FROM customers a JOIN customeritem b ON a.maKhach=b.maKhach JOIN items c ON b.maHang=c.maHang WHERE soLuongMua>1
 
#14.
SELECT a.ten,SUM(donGia*soLuongMua) AS 'Tổng số tiền mua', CASE
WHEN SUM(donGia*soLuongMua)<5000 THEN 'Level1'
    WHEN SUM(donGia*soLuongMua)<1000 THEN 'Level2'
    ELSE 'V.I.P'
    END AS 'Level'
FROM customers a JOIN customeritem b ON a.maKhach=b.maKhach JOIN items c ON b.maHang=c.maHang GROUP BY a.maKhach,a.ten

Solution Practical 5

--2
create database DBLab5;
use DBLab5;

--3
create table Student(
    RN int not null,
    Name nvarchar(25),
    Age int,
    Gender bit,
);
go
create table [Subject](
    [sID] int not null,
    sName varchar(25) ,
);
go
create table StudentSubject(
    RN int not null,
    [sID] int not null,
    Mark int,
    [Date] date,
);

--4
alter table Student add constraint pk1 primary key (RN);
go
alter table [Subject] add constraint pk2 primary key ([sID]);
go
alter table StudentSubject add constraint pk3 primary key (RN,[sID]);
go

--5
alter table StudentSubject add constraint ck1 check(Mark>=0 and Mark<=10);

--6
alter table StudentSubject add constraint fk1 foreign key (RN) references Student(RN);

--7
alter table StudentSubject add constraint fk2 foreign key ([sID]) references [Subject]([sID]);

--8
insert Student(RN,Name) values
                                (1, N'Mỹ Linh'),
                                (2, N'Đàm Vĩnh Hưng'),
                                (3, N'Kim Tử Long'),
                                (4, N'Tài Linh'),
                                (5, N'Mỹ Lệ'),
                                (6, N'Ngọc Oanh');
go
insert [Subject] values
                                (1, 'SQL'),
                                (2, 'LGC'),
                                (3, 'HTML'),
                                (4, 'CF');
go
insert StudentSubject values
                                (1, 1, 8, '7/28/2005'),
                                (2, 2, 3, '7/29/2205'),
                                (3, 3, 9, '7/31/2005'),
                                (4, 1, 5, '7/30/2005'),
                                (5, 4, 10, '7/19/2205'),
                                (6, 1, 9, '7/25/2005');

--9
UPDATE Student SET Gender=0 where RN in(1,4,5);
go
UPDATE Student SET Gender=1 where RN=3;

--10
insert [Subject] values 
                                (5, 'Core Java'),
                                (6, 'VB.Net');

--11
select sName from [Subject] where [sID] not in (select [sID] from StudentSubject);

--12
select sName,Max(Mark) from [Subject] a left join StudentSubject b on a.[sID]=b.[sID] group by sName order by Max(Mark) desc;

--13
select sName from [Subject] where [sID] in (select [sID] from StudentSubject group by [sID] having count([sID])>1)

--14
select b.RN,b.[sID],Name,Age,case Gender
        when 1 then 'Male'        
        when 0 then 'Female'
        else 'Unknow'
        end
        ,sName,Mark,[Date]
        from Student a join StudentSubject b on a.RN=b.RN join [Subject] c on b.[sID]=c.[sID];

--15
create index id1 on Student(Name);
go
create index id2 on [Subject](sName);
go
create index id3 on StudentSubject(RN,[sID]);
go

--16
select top(3) with ties a.RN,Name,Mark,sName,ROW_NUMBER() over(order by Mark desc) as [Rank],GETDATE() as [Date]
into Top3
from Student a join StudentSubject b on a.RN=b.RN join [Subject] c on b.[sID]=c.[sID] order by Mark desc;

select*from Top3

--17
select Name,AVG(Mark) as [Điểm trung bình] from Student a 
    join StudentSubject b on a.RN=b.RN
    group by a.RN,Name
    having AVG(Mark)>=8 and MIN(Mark)>=5

--18
select Name,AVG(Mark ) as [Điểm trung bình] from Student a 
    join StudentSubject b on a.RN=b.RN
    where Mark>=3 and (select COUNT(Mark) from StudentSubject where Mark>=3 and Mark<5)<=1
    group by a.RN,Name
    having AVG(Mark)>=6.5 and MIN(Mark)>=5

Practical 11

I. Tạo một Cơ sở dữ liệu có tên 'BookStore'.

II. Tạo 4 bảng và chèn dữ liệu như sau:

Bảng Students:

StudentID (int, primary key, identity)

Name (VarChar (50))

Age (tinyint)

stGender (bit)

1

Henry

25

1

2

Britney

20

0

3

Beckham

16

Null

4

Madona

17

0

5

Effenberg

30

1

Bảng Books:

BookID (int, primary key, identity)

Name (Varchar (50))

TotalPage (int)

Type (Varchar(10))

Quantity (int)

1

Access 2K

100

Null

3

2

Logic C

60

Null

4

3

HTML

200

Null

2

4

Core Java

50

Null

1

5

SQL 2K

1000

Null

6

Bảng Borrows:

BorrowID (int)

StudentID (int)

BookID (int)

BorrowDate (datetime)

1

1

5

15/09/07

2

2

2

14/09/07

3

2

3

20/09/07

4

2

1

16/09/07

5

2

1

16/09/07

6

3

4

19/09/07

7

4

4

21/09/07

Bảng ReturnBooks:

ReturnID (int)

StudentID (int)

BookID (int)

BorrowDate (datetime)

ReturnDate (datetime)

 

 

 

 

 

Các ràng buộc:

  1. Ràng buộc Check cho cột TotalPage của bảng Books với yêu cầu TotalPage phải lớn hơn 0.

  2. Ràng buộc khóa chính cho các cột StrudentID, BookID, BorrowID và ReturnID của các bảng tương ứng.

  3. Ràng buộc Indetity(1,1) cho cột ReturnID của bảng ReturnBooks.

Các yêu cầu truy vấn:

  1. Cập nhật trường Type trong bảng Books theo tiêu chí:

    • Type='Thin' nếu TotalPage < 100

    • Type='Normal' nếu TotalPage nằm trong đoạn 100 đến 1000

    • Type='Thick' nếu TotalPage > 1000

  2. Hiển thị danh sách sinh viên (danh sách này phải sắp xếp theo trường Age).

  3. Hiển thị tên của sinh viên nhiều tuổi nhất.

  4. HIển thị tổng số sách trong kho.

  5. Hiển thị tên của những sinh viên có stGender là Null.

  6. Hiển thị tên của những sinh viên có ký tự đầu tiên là 'B'.

  7. Hiển thị bookID, borrowDate của những quyển sách được mượn hơn 10 ngày.

  8. Hiển thị ½ tổng số sách.

  9. Viết câu lệnh SQL mô tả hành động: quyển sách 'Access 2K' được trả bởi 'Britney'.

  10. Viết câu lệnh SQL mô tả hành động: quyển sách 'SQL2K' được trả bởi 'Henry'.

  11. Viết câu lệnh SQL mô tả hành động: Madona mượn quyển sách 'SQL2K' vào ngày 28/01/2016.

  12. Viết câu lệnh SQL mô tả hành động: Madona trả quyển sách 'SQL2K' vào ngày 28/03/2016.

Practical 12

CSDL BANHANG lưu trữ thông tin về quản lý bán hàng tại siêu thị Bình Minh ở Hà Nội gồm 6 bảng có cấu trúc như sau:

http://v1study.com/public/images/article/sql-practical12-hinh-1.png

Dữ liệu mẫu trong bảng NhaCungCap:

http://v1study.com/public/images/article/sql-practical12-hinh-1.png

Dữ liệu mẫu trong bảng KhachHang:

http://v1study.com/public/images/article/sql-practical12-hinh-1.png

Dữ liệu mẫu trong bảng NhanVien:

http://v1study.com/public/images/article/sql-practical12-hinh-1.png

Dữ liệu mẫu trong bảng LoaiSanPham:

http://v1study.com/public/images/article/sql-practical12-hinh-1.png

Dữ liệu mẫu trong bảng SanPham:

http://v1study.com/public/images/article/sql-practical12-hinh-7.png

Lưu ý: Trường SoLuongTT có nghĩa là số lượng tối thiểu phải có trong kho. Nếu số lượng đến mức này thì phải nhập hàng từ nhà cung cấp.

Dữ liệu mẫu trong bảng HoaDon:

http://v1study.com/public/images/article/sql-practical12-hinh-8.png

Dữ liệu mẫu trong bảng  HoaDonChiTiet:

http://v1study.com/public/images/article/sql-practical12-hinh-9.png

Hãy viết các lệnh  T-SQL thực hiện các công việc sau:

1.   Trong bảng HoaDonChiTiet cột thành tiền còn chưa được tính toán, hãy cập nhật trường ThanhTien= DonGia*SoLuong*(1-GiamGia).

2.   Sau khi đã có thông tin về ThanhTien  trong HoaDonChiTiet, hãy cập nhật thông tin của trường  Tien trong hóa đơn = tổng số tiền của các mặt hàng có trong hóa đơn = tổng của cột ThanhTien của các bản ghi trong HoaDonChiTiet có cùng số hóa đơn (MaHD). Cập nhật trường TongSoTien=Tien*(1+Thue).

3. Hiển thị danh sách các mặt hàng với đầy đủ các thông tin sau: Loại hàng, mã hàng, tên hàng sắp xếp tăng dần theo tên hàng.

4.   Liệt kê từng mặt hàng và tổng số hàng đã bán (có trong hóa đơn chi tiết) theo từng mặt hàng.

5.   Liệt kê từng mặt hàng và tổng số tiền đã bán (có trong hóa đơn chi tiết) theo từng mặt hàng.

6.   Liệt kê chi tiết các mặt hàng đã bán bao gồm các thông tin sau:

      Số hóa đơn, Mã sản phẩm (hàng), tên sản phẩm, đơn giá, số lượng, giảm giá và thành tiền. Chỉ liệt kê những mặt hàng có giảm giá trên 1% (tức là trường  GiamGia > 0.01), và  ThanhTien <10000.

7.   Hãy liệt kê danh sách khách hàng với đầy đủ các thông tin như: Mã khách hàng, tên khách hàng, địa chỉ, điện thoại, số hóa đơn đã đặt mua hàng trong tháng  3 năm 1997. (Chỉ liệt kê các khách hàng này và sắp xếp theo thứ tự tăng dần của họ và tên).

8.   Liệt kê danh sách các mặt hàng đã bán theo từng loại hàng. Với mỗi loại hàng tính tổng số mặt hàng đã bán, tổng số tiền và cuối cùng có tổng số tất cả mặt hàng đã bán và tổng số tiền.  

9.   Liệt kê danh sách tất cả các khách hàng đã mua hàng trong tháng  11/2006 và tổng số tiền mà họ đã mua.

10  Liệt kê danh sách tất cả các nhân viên và số tiền hàng họ bán được trong tháng  11/2006.

Test Theory cơ bản - SQL

(nhấn nút 'Result' phía cuối bài test để biết kết quả)

Q1: Trong câu truy vấn lấy dữ liệu từ hai bảng đã được gọi là join với nhau, kết quả trả về chỉ gồm các bản ghi nằm trong bảng bên phải . Xác định loại join được dùng trong câu truy vấn trên?
Outer Join
Right Outer Join
Full Join
Right Inner join

Q2: Trong mô hình CSDL phân cấp (Hierarchical Database model), _______ dùng để thiết lập mối quan hệ giữa bảng cha với bảng con
Dollars
Pointers
Line
Bảng cha và bảng con ko thể thiết lập mối quan hệ

Q3: Mô hình CSDL mà một bảng con có nhiều bảng cha thuộc loại _______
Mô hình CSDL (Flat-file Database model)
Mô hình CSDL phân cấp (Hierarchical Database Model)
Mô hình CSDL mạng (Network Systems Database Model)

Q4: Chỉ ra cú pháp để tạo một bảng bằng T-SQL
CREATE TABLE (<Table_name>)
CREATE TABLE <Table_Name>(<Column_name)(Data_Type>)
CREATE TABLE (<Column_name><Data_Type>)
CREATE TABLE <Table_Name>(<Column_name>)

Q5: Khi muốn xóa bảng Books trong CSDL, cú pháp nào dưới đây được sử dụng?
DROP Books
DROP TABLE Books FROM library
DROP TABLE Books
DELETE TABLE Books
DELETE TABLE Books FROM library

Q6: Một câu lệnh truy cập vào dữ liệu trong CSDL gọi là _______
Transaction
Operation
Query
Statement

Q7: Khi sử dụng bất kỳ hàm tập hợp nào trong câu lệnh SELECT, chỉ nên sử dụng hàm đó trên trường đầu tiên trong câu lệnh SELECT
Đúng
Sai

Q8: Đâu là cú pháp đúng cho hàm AVG?
AVG([DISTINCT] Biểu Thức)
AVG([ALL|DISTINCT] Biểu Thức)
AVG(Biểu Thức)
AVG([ALL]Biểu Thức)
Tất cả các lựa chọn trên

Q9: Phát biểu nào dưới đây là đúng về hàm COUNT? (chọn 3)
Khi sử dụng hàm COUNT trên trường khóa chính luôn trả về kết quả chính xác do trường khóa chính ko có các giá trị null
Khi được dung kết hợp với từ khóa DISTINCT, hàm COUNT chỉ đếm những giá trị riêng biệt
Cú pháp của hàm COUNT chỉ thực hiện trên những trường có kiểu dữ liệu là số
Cú pháp hàm COUNT là COUNT(Biểu thức)
Khi sử dụng hàm COUNT trên trường khóa ngoại có thể trả về kết quả không chính xác do trường khóa ngoại có thể có các giá trị null

10: DML viết tắt bởi
Data Moulding Language
Data Manipulation Language
Data Modeling Language
Data Marketing Language

Q11: Những kiểu dữ liệu nào dưới đây được hỗ trợ bởi SQL 2005 (chọn 3)
String
Date
Tinyint
Ntext
Double

Q12: Giả sử bạn có 1 bảng tên A, trong bảng đó có trường tên là 'xyz' với kiểu dữ liệu là int . Giá trị của tất cả các trường trong 1 bản ghi của bảng đó phải là giá trị số nguyên
Đúng
Sai

Q13: RDBMS hỗ trợ hệ thống lưu trữ CSDL phân tán
Đúng
Sai

Q14: Phát biểu nào dưới đây là đúng về Join?
Join có thể được sử dụng trong mệnh đề FROM . Trong các truy vấn có mệnh đề WHERE thì không được sử dụng Join
Trong SQL Server 2005 các bảng được Join với nhau dựa trên mối quan hệ trên các bảng đó
Join chỉ ra mối quan hệ giữa 2 bảng
Khi được sử dụng, Join sẽ loại bỏ khái niệm về quan hệ khóa ngoại giữa các bảng
Join chỉ có thể dùng trên 2 bảng

Q15: Để cập nhật dữ liệu ở mức độ trường, câu lệnh nào dưới đây được sử dụng?
UPDATE Table_name, Column_name
UPDATE Table_name SET (Column_name)
Column_name UPDATE
UPDATE Column_name
UPDATE ( Column_name )

Q16: Phát biểu nào dưới đây là sai? (chọn 2)
Outer joins sẽ trả về tất cả các bản ghi của 1 bảng nào đó trong mệnh đề FROM, nếu những bản ghi đó thỏa mãn những điều kiện trong mệnh đề WHERE và HAVING
Có 4 loại outer joins
Inner hoins trả về tất cả cacs bản ghi ngay cả khi ko có bản ghi nào tương ứng với nó trong bảng lien quan
Inner hoins loại bỏ những bản ghi mà ko có bản ghi nào tương ứng với nó trong bảng liên quan

Q17: Xác định cú pháp đúng cho LEFT OUTER JOIN
LEFT OUTER TABLE SELECT <Field_List> from <First_table><Second_table> ON
   First_Table.<common_Field>=Second_Table.<common_Field>
SELECT <Field_List> from <First_table> LEFT OUTER TABLE <Second_table> ON
   First_Table.<common_Field>=Second_Table.<common_Field>
SELECT <Field_List> from <First_table> LEFT OUTER JOIN <Second_table> ON
   First_Table.<common_Field>=Second_Table.<common_Field>
SELECT <Field_List> from <First_table> LEFT OUTER JOIN <Second_table> WHERE
   First_Table.<common_Field>=Second_Table.<common_Field>
Q18: Toàn vẹn thực thể còn được gọi là _______
Database Integrity (Toàn vẹn CSDL)
Table Integrity (Toàn vẹn bảng)
Column Integrity (Toàn vẹn cột)
Row Intergrity (Toàn vẹn dòng)

Q19: Thuật ngữ miền (domain) chỉ ra một tập hợp các giá trị được phép lưu trữ trong một trường
Sai
Đúng

Q20: Khi phải lựa chọn khóa chính giữa 1 trường đơn và trường phức, tốt hơn nên chọn trường phức (composite key)
Đúng
Sai

Q21: Dữ liệu trong trường khóa chính phải được thay đổi thường xuyên để đảm bảo tính phân biệt của bản ghi (identity of the row)
Đúng
Sai

Q22: Tìm phát biểu đúng
 
 Phát biểu 1 – Bảng được tạo ra để lưu trữ thực thể
 Phát biểu 2 – Các trường được tạo ra để thể hiện các thuộc tính của thực thể
Phát biểu 2 là đúng
Phát biểu 1 là đúng
Cả 2 phát biểu đều đúng
Không có phát biểu nào đúng

Q23: Xác định khóa chính và khóa ngoại cho các bảng dưới đây
 Patient: Patient_Code, Patient_Name, Address, Age, Physician_Code (Bệnh nhân)
 Prescription : Patient_Code, Drug, date, Amount, Caution, Physician_Code (Đơn thuốc)
Physician_Code, Patient_Code
Patient_Code, Physician_Code
Patient_Code, date
Patient_Name, Patient_Code

Q24: Những yếu tố nào dưới đây được xem xét trong quá trình xác định khóa chính cho bảng ?
Tình đồng bộ và tính chính xác (Concurrency and Accuracy)
Tính tối thiểu và tính xác định (Minimality and Definiteness)
Tính tin cậy và tính đồng bộ (Reliability and Concurrency)
Tính tối thiểu và tính bảo mật (Minimalyti and Security)

Q25: Tìm ra phát biểu đúng về toàn vẹn tham chiếu?
Toàn vẹn tham chiếu ko đảm bảo tính nhất quán về giá trị của trường khóa trong các bảng
Toàn vẹn tham chiếu đảm bảo mối quan hệ giữa các bảng ko bị mất thao tác trên các bản ghi
Toàn vẹn tham chiếu đảm bảo khi giá trị của trường khóa bị thay đổi, tất cả các tham chiếu đến nó cũng được thay đổi theo

Q26: Xác định phát biểu đúng về khóa chính? (chọn 3)
Ràng buộc khóa chính có thể được thay đổi khi cần thiết
Khi một khóa chính được tham chiếu bởi 1 khóa ngoại, ta ko thể xóa khóa chính đó
Một bảng có thể có nhiều hơn 1 khóa chính
Khóa chính có chức năng phân biệt từng bản ghi trong bảng

Q27: Tìm ra phát biểu đúng? (chọn 2)
Để tạo mối quan hệ trên các bảng, các bảng đó phải có cùng số trường và các trường phải giống nhau về kiểu dữ liệu
Các bảng có quan hệ với nhau dựa trên các trường chung
Các bảng có quan hệ với nhau phải nằm trong cùng 1 CSDL
Một mối quan hệ là một sự tương ứng giữa hai bảng

28: Mỗi ràng buộc toàn vẹn đều có bốn yếu tố cấu thành: điều kiện, bối cảnh, bảng tầm ảnh hưởng và hành động cần phải thực hiện khi phát hiện có ràng buộc toàn vẹn bị vi phạm
Sai
Đúng

Q29: Bảo mật CSDL được thực hiện bởi DBA (DataBase Administrator)
Sai
Đúng

Q30: Mô hình CSDL Flat – file gồm nhiều bảng
Đúng
Sai

Q31: Khóa ngoại là trường mà giá trị của nó trùng với khóa duy nhất (unique key), không trùng với khóa chính (primary key)
Đúng
Sai

Q32: Để phân biệt từng bản ghi trong bảng, có thể sử dụng
Primary key
Foreign Key
Unique key

Q33: Trong Sơ đồ thực thể quan hệ (ER-Diagram), hình elip dùng để thể hiện _________
Mối quan hệ giữa các thực thể
Thực thể trong CSDL
Thuộc tính của thực thể

Q34: Kiểu Image lưu trữ dữ liệu nhị phân với độ dài thay đổi từ 0 đến 2^31-1 bytes
Đúng
Sai

Q35: Phát biểu nào là đúng với thuộc tính Identity?
Thuộc tính Identity có thể áp dụng cho nhiều cột trong một bàng
Cột áp dụng Identity không thể NULL
Cột áp dụng Identity có thể là kiểu char
Cột áp dụng Identity có thể NULL


Q36: Chỉ ra một số thuận lợi khi sử dụng CSDL tập trung (chọn 2)
Dữ liệu có thể dùng chung cho nhiều người
Làm tăng dữ liệu dư thừa trong CSDL
Giảm thiểu dữ liệu không thống nhất trong CSDL
Không thể tích hợp được dữ liệu
Không cần bảo mật đối với CSDL tập trung

Q37: Một bảng trong SQL Server 2005 cho phép đặt nhiều ràng buộc UNIQUE
Sai
Đúng

Q38: Update Employee set Sal = Sal + (Sal * .20) where Sal between 2000 and 4000
Truy vấn trên cho kết quả là gì?
Câu truy vấn sẽ tăng lương 20% ​​cho nhân viên có mức lương là 2000 và 4000
Câu truy vấn sẽ tăng lương 20% ​​cho nhân viên có lương từ 2000 đến 4000, bao gồm cả nhân viên có mức lương là 2000 và 4000.
Câu truy vấn sẽ tăng lương 20% ​​cho nhân viên có lương từ 2000 đến 4000, không bao gồm nhân viên có lương là năm 2000 và 4000.

Q39: Trong SQL Server 2005, kiểu dữ liệu alphanumeric được hiểu là kiểu dữ liệu Text, có độ dài biến đổi với kích thước tối đa là _______ ký tự?
2^21-1
2^31-1
1^41-1
2^51-1

Q40: Lựa chọn kiểu dữ liệu phù hợp với tên trường
 a Patient_name      1 Autonumber
 b Patient_ID        2 Memo
 c Patient_Adm_Date  3 Text
 d Patient_History   4 DateTime
a-3, b-1, c-4, d-2
a-2, b-1, c-4, d-3
a-4, b-3, c-1, d-2
a-3, b-4, c-1, d-2

Q41: Cú pháp để tạo ra một bảng với ràng buộc cho các trường của bảng là:
CREATE TABLE <table constraint> <table name>(<column_definition> <table_constraint>)
CREATE TABLE <table name>(<table_constraint> <column_definition>)
CREATE TABLE <table name>(<column_definition> <table_constraint>)
CREATE TABLE <table name>(<table_constraint>)

Q42: Đâu là phát biểu dúng?
 
 Phát biểu 1: Nên thiết lập khóa chính trên trường đơn thay vì trường phức hợp
 Phát biểu 2: Thao tác với một cột nhanh hơn so với thao tác với nhiều cột
Cả hai phát biểu đều đúng và phát biểu 2 là lý do cho phát biểu 1
Cả hai phát biểu đều đúng và phát biểu 2 không phải là lý do cho phát biểu 1
Chỉ có phát biểu 2 đúng
Cả hai phát biểu đều sai

Q43: Loại chuẩn hóa nào yêu cầu trường không khóa phải phụ thuộc vào trường khóa trong một bảng?
1NF
2NF
3NF

Q44: Những cơ chế nào được cung cấp bởi SQL Server 2005 đảm bảo tính toàn vẹn của thực thể?
Primary key
thuộc tính Identity
Unique key
ràng buộc Check
Foreign key

Q45: Xác định truy vấn hợp lệ để lấy thông tin của các khách hàng có số điện thoại?
SELECT * from customer where phone IS NOT NULL
SELECT * from customer where phone = NOT NULL
SELECT * from customer where phone NOT NULL
SELECT * from customer where HAVING phone NOT NULL

Q46: SQL Server 2005 lưu trữ ngày tháng theo định dạng __________ và __________
mm/dd/yy
dd-mon-yy
dd-mm-yy
dd/mm/yy
yy-mm-dd

Q47: Ràng buộc Rrimary key trong bảng hiện tại không thể bị xóa nếu bảng đó đang được tham chiếu bởi một ràng buộc Foreign key trong bảng khác, muốn xóa được phải xóa Foreign key trước
Đúng
False

Q48: Đâu là công cụ của SQL 2005 để thực thi toàn vẹn miền?
định nghĩa DEFAULT
ràng buộc PRIMARY key
ràng buộc FOREIGN key
ràng buộc CHECK
ràng buộc NOT NULL

Q49: Đâu là phát biểu đúng?
 
 Phát biểu 1: Ràng buộc FOREIGN key chỉ có thể liên kết được với cột chứa ràng buộc PRIMARY key
    trong bảng khác
 Phát biểu 2: Ràng buộc FOREIGN key có thể tham chiếu tới cột chứa ràng buộc UNIQUE trong bảng khác
Chỉ phát biểu 1 Đúng
Chỉ phát biểu 2 Đúng
Cả hai phát biểu Đúng
Cả hai phát biểu Sai

Q50: Điều gì sẽ xảy ra nếu có các bản ghi trong một bảng khác liên kết với các bản ghi đang muốn xóa của bảng hiện tại?
Lệnh xóa không thể thực hiện được
Các bản ghi của bảng hiện tại sẽ bị xóa
Các bản ghi của bảng hiện tại cũng như các bản ghi của bảng khác liên quan sẽ bị xóa

Q51: Câu lệnh nào thể hiện lương của tất cả các nhân viên tăng thêm 10%?
SELECT emp_code, basic * 0.10 from employee order by emp_code
SELECT emp_code, basic + basic*0.01 from employee order by emp_code
SELECT emp_code, basic + 10 from employee order by emp_code
SELECT emp_code, basic + basic * 0.10 from employee order by emp_code

Q52: File cơ sở dữ liệu nào luôn luôn hiện diện trong cơ sở dữ liệu?
Primary data files
Log files
Secondary data files
Command data files

Q53: Nếu bạn truy cập SQL Server bằng chế độ Windows Authentication, thì bạn phải cung cấp một ID đăng nhập mỗi khi bạn truy cập
Đúng
Sai

Q54: Hai giá trị NULL có bằng nhau không?

Không

Q55: ___________ đảm bảo việc giới hạn các giá trị nhập vào cho một cột cụ thể
Toàn ven thực thể
Toàn vẹn do người dùng định nghĩa
Toàn vẹn miền
Toàn vẹn tham chiếu

Q56: Đâu là phát biểu đúng đối với ràng buộc UNIQUE?
Ràng buộc UNIQUE được sử dụng khi chúng ta muốn đảm bảo tính duy nhất của một cột không phải là khóa chính
Mỗi ràng buộc UNIQUE chỉ có thể được định nghĩa trên một bảng
Ràng buộc UNIQUE có thể được tham chiếu bởi ràng buộc FOREIGN key
Ràng buộc UNIQUE có thể được định nghĩa trên các cột cho phép giá trị NULL

Q57: Đâu là câu lệnh xóa tất cả các hàng từ một bảng?
DROP Tên_bảng
DELETE Tên_bảng
DELETE Tên_các_hàng
TRUNCATE TABLE Tên_bảng

Q58: Đâu là câu truy vấn cập nhật giá sách tăng 10%?
UPDATE BookDetails SET Book_Price*10/100
UPDATE BookDetails SET Book_Price = Book_Price*10/100
UPDATE Book_Price = Book_Price + Book_Price*10/100 FROM BookDetails
UPDATE BookDetails SET Book_Price = Book_Price + Book_Price * 10/100

Q59: Nếu chỉ muốn xem các bản ghi trong bảng Student, trong đó trường regis_dt có giải giá trị nằm trong đoạn từ '10/02/2004' đến '12/02/2004', thì câu lệnh nào dưới đây đáp ứng được yêu cầu?
SELECT * FROM Student WHERE regis_dt BETWEEN '10/02/2004' AND '12/02/2004'
SELECT * FROM Student WHERE regis_dt BETWEEN #10/02/2004# AND #12/02/2004#
SELECT * FROM Student WHERE regis_dt NOT BETWEEN #10/02/2004# AND #12/02/2004#

Q60: Câu lệnh DML có thể thực hiện một hành động đơn lẻ trên một hàng đơn lẻ
Đúng
False

Q61: SQL Server 2005 có thể hoạt động như một hệ thống cơ sở dữ liệu Client/Server
Đúng
False

Q62: Bảng được sử dụng trong mệnh đề FROM của câu lệnh truy vấn được gọi là bảng _________
Parent
Base
Related
Like

Q63: Ràng buộc UNIQUE không thể được tham chiếu bởi một khóa FOREIGN?
Đúng
Sai

Q64: Đâu là hai hàm tập hợp thống kê chỉ áp dụng được cho các cột chứa giá trị số?
Sum()
Avg()
Count()
Max()

Q65: Đâu là những đặc điểm của cơ sở dữ liệu chuẩn hóa?
Tất cả các trường phải chứa dữ liệu
Mỗi bảng phải có một trường khóa
Một bảng có thể chứa các trường giống nhau
Mỗi bảng phải có nhiều hơn một bản ghi
Tất cả các trường không khóa phải độc lập với nhau

Q66: Các tập lệnh SQL khác nhau không thể được thực thi dựa trên các điều kiện xác định
Đúng
False

Q67: Đâu là phát biểu đúng đối với T-SQL?
T-SQL được gọi là Transact SQL
T-SQL có thể được sử dụng để truy xuất dữ liệu
T-SQL có thể được sử dụng để kết hợp dữ liệu
T-SQL có thể được sử dụng để truy vấn trên nhiều bảng
T-SQL không phù hợp để sử dụng cho tóm lược dữ liệu

Q68: Đâu là những toán tử dùng trong truy vấn?
%
!
<>
@

Q69: Bảng Account chứa thông tin chi tiết tiền lương của tất cả các nhân viên trong công ty. Một trong những nhân viên của công ty có tên 'James' có EmployeeID E210 nhận khuyến mãi. Thông tin chi tiết về chương trình khuyến mãi phải được cập nhật vào trong bảng Account. Đâu là gợi ý câu lệnh cập nhật đúng?
Update ... WHERE EmployeeID = E210
INSERT INTO Account ... WHERE EmployeeID = E210
Update Account ... WHERE EmployeeID = E210

Q70: Thông tin trong SQL Server được lưu trữ ở mức __________
Table
Database
Byte
Page

Q71: Câu lệnh nào sau đây sẽ trả về tất cả các tên trong bảng Account với điều kiện tên phải chứa ký tự 'e' nhưng không được nằm ở đầu?
SELECT * FROM Account WHERE Name like 'e'
SELECT Name FROM Account WHERE Name like '%e'
SELECT * FROM Account WHERE Name like '&e'
SELECT * FROM Account WHERE Name like '%e%'
SELECT Name FROM Account WHERE Name like '[^e]%e%'

Q72: Cho câu lệnh sau: "SELECT TOP 100 <column_name> FROM <table_name>". Nếu bảng có 10 bản ghi thì kết quả là gì?
Phát sinh lỗi
Trả về 10 giá trị của cột tương ứng
Trả về tất cả các hàng và các cột của bảng
Trả về 10 hàng dữ liệu và 90 hàng trống

Q73: Chọn phát biểu đúng
Trong T-SQL, một biểu thức có thể có nhiều toán tử, các toán tử được phân định theo thứ tự ưu tiên
Toán tử LIKE được dùng để so sánh một chuỗi ký tự với một mẫu
T-SQL chấp nhận toán tử "!="
Một biểu thức có thể có nhiều toán tử và định hướng ưu tiên từ phải sang trái

Q74: Tìm phát biểu đúng?
Cột phân biệt được các bản ghi trong một bảng thì được hiểu là khóa chính
Khóa chính sẽ đảm bảo tính toàn vẹn miền
Mỗi bảng có thể có nhiều khóa chính
Mỗi bảng chỉ có một khóa chính

Q75: Đâu là cú pháp đúng của thuộc tính IDENTITY?
Tên_cột Kiểu_dữ_liệu IDENTITY(SEED,INCREMENT)
Tên_cột Kiểu_dữ_liệu IDENTITY(???)
Tên_cột IDENTITY(SEED,INCREMENT)
Tên_cột Kiểu_dữ_liệu IDENTITY

Q76: Bạn muốn xem nhân viên được trả lương cao nhất trong từng phòng ban. Từ khoá nào sau đây sẽ được sử dụng trong câu truy vấn để đáp ứng được yêu cầu đó?
UNION
ORDER BY
INTERSECT
IN
GROUP BY

Q77: Donald muốn chuẩn hóa dữ liệu. Lời khuyên của bạn là gì?
Chuẩn hóa khi dữ liệu lớn và phân tán
Chuẩn hóa khi dữ liệu phức tạp
Chuẩn hóa khi dữ liệu được phân nhóm
Chuẩn hóa là bước đầu tiên để xây dựng ứng dụng cơ sở dữ liệu

Q78: Trong SQL Server 2005 khi đã xóa một bảng nào đó trong cơ sở dữ liệu thì có thể khôi phục được không?

Không

Q79: Đâu là phát biểu đúng?
 
 Phát biểu 1: INNER JOIN loại bỏ các hàng không phù hợp với một hàng từ một bảng khác
 Phát biểu 2: OUTER JOIN sẽ trả về tất cả các hàng từ ít nhất một bảng được đề cập đến trong mệnh đề FROM nếu các hàng đó thỏa mãn các điều kiện tìm kiếm WHERE hoặc HAVING trong câu lệnh SELECT
Chỉ phát biểu 1 ĐÚNG
Chỉ phát biểu 2 ĐÚNG
Cả 2 phát biểu đều ĐÚNG
Cả 2 phát biểu đều SAI

Q80: Câu lệnh SQL nào sẽ trả về tên của nhân viên nhận lương cao nhất trong mỗi phòng ban của công ty?
select employeename, dept_code, salary from employee where employee.salary =(select Max(salary) from Employee group by dep_code)
select employeename, dept_code, salary from employee where employee.salary in (select Max(salary) from Employee group by dep_code having Max(salary))
select employeename, dept_code, salary from employee where employee.salary in (select Max(salary) from Employee group by dep_code)
select employeename, dept_code, salary from employee where employee.salary in (select (salary) from Employee group by dep_code having Max(salary))

Q81: Khi một ràng buộc CHECK được thêm vào một bảng đã có dữ liệu thì mặc định dữ liệu có sẵn được coi là dữ liệu mới
Đúng
Sai

Q82: Joe đang làm một dự án Thư viện. Anh ấy thiết kế cơ sở dữ liệu cho hệ thống. Hệ thống thực hiện việc chuyển các bản ghi rất ổn định. Bạn khuyên anh ấy nên sử dụng thành phần nào của SQL Server?
DQL
DDL
DML
CCL

Q83: Thành phần nào của SQL Server dùng để quản lý quyền truy cập đối với Admin vào cơ sở dữ liệu và đối tượng cơ sở dữ liệu?
DML
Sub-schema DDL
DCL
DDL

Q84: Đâu là những ưu điểm của mô hình cơ sở dữ liệu mạng?
Dễ thực hiện các mối quan hệ
Dễ thiết kế cơ sở dữ liệu
Mô hình đảm bảo tính toàn vẹn dữ liệu
Mô hình đảm bảo tính độc lập của dữ liệu
Tất cả các ưu điểm trên


 

(Ghi chú: Phần câu hỏi Qi có màu Green thể hiện đáp án đúng)

Test Theory nâng cao - SQL

Solution Practical 6

--2
create database DBLab6
go
use DBLab6
go

--3
create table Students(
    StudentID int not null,
    Name varchar(50),
    Age tinyint,
    stGender bit,
);
go
create table Projects(
    PID int not null,
    PName varchar(50),
    Cost float,
    [Type] varchar(10),
);
go
create table StudentProject(
    StudentID int not null,
    PID int not null,
    WorkDate date,
    Duration int,
);
go
insert Students values
                            (1, 'Joe Hart', 25, 1),
                            (2, 'Colin Doyle', 20, 1),
                            (3, 'Paul Robinson', 16, NULL),
                            (4, 'Luis Garcia Paulson', 17, 0),
                            (5, 'Ben Foster', 30, 1);
go
insert Projects(PID,PName,Cost) values
                            (1, 'NewYork Bridge', 100),
                            (2, 'Tenda Road', 60),
                            (3, 'Google Road', 200),
                            (4, 'The Star Bridge', 50);
go
set dateformat dmy;
go
insert StudentProject values
                            (1, 4, '15/05/09', 3),
                            (2, 2, '14/05/09', 5),
                            (2, 3, '20/05/09', 6),
                            (2, 1, '16/05/09', 4),
                            (3, 1, '16/05/09', 6),
                            (3, 4, '19/05/09', 7),
                            (4, 4, '21/05/09', 8);
go

--4a
alter table Students add constraint ck1 check (Age>15 and Age<33);
go

--4b
alter table Students add constraint pk1 primary key (StudentID);
go
alter table Projects add constraint pk2 primary key (PID);
go
alter table StudentProject add constraint pk3 primary key (StudentID,PID);
go

--4c
alter table StudentProject add constraint df1 default(0) for Duration;
go

--4d
alter table StudentProject add constraint fk1 foreign key (StudentID) references Students(StudentID);
go
alter table StudentProject add constraint fk2 foreign key (PID) references [Projects](PID);
go

--5
update Projects set [Type]=case 
    when Cost<80 then 'Education'
    when Cost between 80 and 150 then 'Normal'
    else 'Government'
end;
go

--6
select Name from Students where StudentID in (select StudentID from StudentProject group by StudentID having count(PID)>1);
go

--7
select Name from Students where StudentID in (select top(1) with ties StudentID from StudentProject group by StudentID order by SUM(Duration) desc)
go

--8
select Name from Students a
join StudentProject b on a.StudentID=b.StudentID 
join Projects c on b.PID=c.PID
where Name like '%Paul%' and PName='The Star Bridge';
go

--9
select Name from Students where StudentID not in (select StudentID from StudentProject)
go

--10
create view vwStudentProject as
    select top(99.99) percent Name, PName, WorkDate, Duration from Students a
    full join StudentProject b on a.StudentID=b.StudentID
    full join Projects c on b.PID=c.PID
    order by Name asc;
go
select*from vwStudentProject;
go

--11
alter view vwStudentProject with encryption,schemabinding as
    select Name, PName, WorkDate, Duration from dbo.Students a
    join dbo.StudentProject b on a.StudentID=b.StudentID
    join dbo.Projects c on b.PID=c.PID;
go
create unique clustered index ixStudentName on vwStudentProject(Name,PName)
go

--12
create proc spWorkin(@Name varchar(50)) as
Begin
    if(exists(select*from Students where Name like '%'+@Name+'%'))
        select Name,PName from Students a
        join StudentProject b on a.StudentID=b.StudentID 
        join Projects c on b.PID=c.PID
        where Name like '%'+@Name+'%';
    else if(@Name='any')
        select Name,PName from Students a
        full join StudentProject b on a.StudentID=b.StudentID 
        full join Projects c on b.PID=c.PID;
    else
        print N'Không có sinh viên nào tương tự '+@Name;
End;
go
exec spWorkin 'Luis'
go

--13
create trigger tgUpdateTrig on Students instead of update as
Begin
    alter table StudentProject drop constraint fk1;
    update Students set StudentID=(select StudentID from inserted) where StudentID=(select StudentID from deleted);
    update StudentProject set StudentID=(select StudentID from inserted) where StudentID=(select StudentID from deleted);
    alter table StudentProject add constraint fk1 foreign key (StudentID) references Students(StudentID);
End;
go
update Students set StudentID=6 where StudentID=2
go
select*from StudentProject
go

--14
create proc spDropOut(@PName varchar(50)) as
Begin
    If(exists(select*from Projects where PName like '%'+@PName+'%'))
    Begin
        Delete from StudentProject where PID in (select PID from Projects where PName like '%'+@PName+'%')
        Delete from Projects where PName like '%'+@PName+'%'
    End;
End;
go
exec spDropOut 'The'

Solution Practical 7

create database DBLab7;
use DBLab7;

--Tạo bảng
create table Customer(
    CustomerID int not null,
    Name varchar(30),
    Birth date,
    Gender bit,
);

create table Product(
    ProductID int not null,
    Name varchar(30),
    Pdesc text,
    Pimage varchar(200),
    PStatus bit,
);

create table Comment(
    ComID int identity(1,1),
    ProductID int not null,
    CustomerID int not null,
    Data datetime,
    Title varchar(200),
    Content text,
    [Status] bit,
);

--Tạo ràng buộc Default
alter table Comment add constraint df1 default(getdate()) for Data;

--Khóa chính
alter table Customer add constraint pk1 primary key (CustomerID);
alter table Product add constraint pk2 primary key (ProductID);
alter table Comment add constraint pk3 primary key (ComID);

--Khóa ngoại
alter table Comment add constraint fk1 foreign key (ProductID) references Product(ProductID);
alter table Comment add constraint fk2 foreign key (CustomerID) references Customer(CustomerID);

--Tạo ràng buộc Unique
alter table Product add constraint un1 unique(Pimage);

----------Nhập liệu------------------

insert Customer values    (1,'Jonny Owen','10/10/1980',1),
                        (2,'Christina Tiny','03/10/1989',0),
                        (3,'Garry Kelley','03/16/1990',null),
                        (4,'Tammy Beckham','05/17/1980',0),
                        (5,'David Phantom','12/30/1987',1);

insert Product values    (1,'Nokia N90','Mobile Nokia','image1.jpg',1),
                        (2,'HP DV6000','Laptop','image2.jpg',null),
                        (3,'HP DV2000','Laptop','image3.img',1),
                        (4,'Samsung G448','Mobile Samsung','image4.img',0),
                        (5,'LCD Plasma','TV LCD','image5.img',0);

insert Comment values    (1,1,'03/15/09','Hot product',null,1),
                        (2,2,'03/14/09','Hot price','Very much',0),
                        (3,2,'03/20/09','Cheapest','Unlimited',0),
                        (4,2,'04/16/09','Sale off','50%',1);

---------------Truy vấn------------------------

--4.
select Name,PStatus from Product where PStatus=0 or PStatus is NULL;

--5.
select Name from Product where ProductID not in (select ProductID from Comment);

--6.
select top(1) with ties Name,count(ComID) as [So binh luan] from Customer a join Comment b on a.CustomerID=b.CustomerID group by Name order by count(ComID) DESC;

--7.
--Tạo View
create view vwFull_Information AS
    select b.ComID,a.Name as [ten khach],c.Name as [ten hang],b.Data,b.Title,b.Content,[Status]= case b.[Status]
                                                                when 0 then 'Not Accept'
                                                                when 1 then 'Accept'  
                                                                else 'Unknow' end
    from Customer a join Comment b on a.CustomerID=b.CustomerID join Product c on b.ProductID=c.ProductID;

--Xem view
select * from vwFull_Information;

--8.
create view vwCustomerList AS
    select CustomerID,Name as [CustomerName],Birth,GENDER= case Gender when 1 then 'Male'
                                                     when 0 then 'Female'  
                                                     else 'Unknow' end,
            [Status]= case when datediff(YY,Birth,getdate()) >=30 then 'Old'
                           when datediff(YY,Birth,getdate()) <30  then 'Young'
                           else 'Unknow' end
    from Customer ;

--Xem view
select * from vwCustomerList; 

--9.
alter view vwCustomerList with schemabinding AS 
    select CustomerID,Name as [CustomerName],Birth,Gender from dbo.Customer;
create unique clustered index ixCustomerName on vwCustomerList([CustomerName]);

--10.
create proc spStudent (@Name varchar(30)) AS
    Begin
        if(Exists(select Name from Product where Name like '%' + @Name + '%'))
            select a.Name as [Ten SP],Data,Title,Content from Product a join Comment b on a.ProductID=b.ProductID where Name like '%'+ @Name +'%'; 
        else if(Exists(select Name from Customer where Name like '%'+ @Name +'%'))
            select a.Name as [Ten Khach],Data,Title,Content from Customer a join Comment b on a.CustomerID=b.CustomerID where Name like '%'+@Name+'%';
        else if(@Name='*')
            select Name as [Ten SP],Data,Title,Content from Product a join Comment b on a.ProductID=b.ProductID;
        else 
            print 'Khong tim thay '+@Name;
    End; 

--Check SP
EXEC spStudent 'Nokia';
EXEC spStudent 'Jonny';
EXEC spStudent '*';
EXEC spStudent 'LoL';

--11.
create trigger tgUpdateProduct on Product instead of update AS
    if Update (ProductID)
    begin
        alter table Comment drop constraint fk1
        update Product set ProductID=(select ProductID from inserted) where ProductID=(select ProductID from deleted)
        update Comment set ProductID=(select ProductID from inserted) where ProductID=(select ProductID from deleted)
        alter table Comment add constraint fk1 foreign key (ProductID) references Product(ProductID);
    end;

--Check Trigger
update Product set ProductID=10 where ProductID=1;
select * from Product;
select * from Comment;

update Product set ProductID=1 where ProductID=10;

--12.
create proc spDropUot (@Name varchar(30)) AS
    Begin 
        if(Exists (select Name from Customer where Name = @Name))
            Begin
            delete from Comment where CustomerID in (select CustomerID from Customer where Name = @Name)
            delete from Customer where Name = @Name
            End;
        else
            print 'Khong tim thay khach hang ten '+@Name;
    End;

-- check SP
EXEC spDropUot 'Victor'

Solution Practical 10

1. Video hướng dẫn:

2. Code: 

--2.
create database DBLab8;
use DBLab8;
--3.
create table Food(
fID int not null,
Name nvarchar(30),
Price money
);
alter table Food add constraint
pk_fID primary key(fID);
insert Food values
(1,N'Gà hấp xì dầu',27000),
(2,N'Sườn nõn sốt chanh',33000),
(3,N'Bò xào hành tỏi',23000),
(4,N'Cá thu sốt',31000);
select*from Food;
create table FoodStuff(
sID int not null,
Name nvarchar(30),
Type int
);
alter table FoodStuff add constraint
pk_sID primary key(sID);
insert FoodStuff values
(1,N'Thịt gà',1),
(2,N'Thịt lơn',1),
(3,N'Thịt bò',1),
(4,N'Cá thu',1),
(5,N'Hành',2),
(6,N'Tỏi',2),
(7,N'Cà chua',2),
(8,N'Xì dầu',2),
(9,N'Chanh',2),
(10,N'Hạt tiêu',2);
select*from FoodStuff;
create table FoodDetail(
fID int not null,
sID int not null
);
alter table FoodDetail add
constraint pk_fID_sID primary key(fID,sID),
constraint fk_fID foreign key(fID) references Food(fID),
constraint fk_sID foreign key(sID) references FoodStuff(sID);
insert FoodDetail values
(1,1),
(1,8),
(2,2),
(2,9),
(2,7),
(2,5),
(3,3),
(3,5),
(3,6),
(4,4),
(4,7);
--4.
select a.Name as [Món ăn],
c.Name as [Thực phẩm]
from Food a join FoodDetail b
on a.fID=b.fID join FoodStuff c
on b.sID=c.sID
order by a.Name;
--5.
select*from FoodStuff where
sID not in(select sID from FoodDetail);
--6. Những thực phẩm dùng cho nhiều
--hơn 1 món ăn là những thực phẩm
--có mã xuất hiện nhiều hơn 1 lần trong
--bảng FoodDetail:
select Name from FoodStuff a join
FoodDetail b on a.sID=b.sID
group by Name having COUNT(a.sID)>1;
--7. Món ăn được chế biến từ nhiều loại
--thực phẩm nhất tức là có nhiều mã
--của loại thực phẩm nhất quan hệ với
--mã của món ăn đó.
select top(1) with ties Name from
Food a join FoodDetail b on a.fID=b.fID
group by Name order by COUNT(a.fID) desc;
--8.
select Name,Type = case Type
when 1 then N'Thực phẩm chính'
else N'Gia vị'
end
from FoodStuff;
--9.
create view vw_FoodList as
select top(99.99) percent * from
Food order by Price desc;
select*from vw_FoodList;
--10.
update Food set Price*=1.1;
select*from Food;
update Food set Price/=1.1;
select*from Food;
--11.
create proc sp_FoodChoice(@Price money) as
begin
select*from Food where Price<@Price;
end;
----Thử nghiệm:
exec sp_FoodChoice 30000;
--12.
alter proc sp_FoodChoice(@Name nvarchar(30),@Type nvarchar(3)) as
begin
if(@Type=N'Rẻ')
select a.Name,Price from Food
a join FoodDetail b on a.fID=b.fID
join FoodStuff c on b.sID=c.sID
where c.Name like'%'+@Name+'%'
and Price<30000;
else if(@Type=N'Đắt')
select a.Name,Price from Food
a join FoodDetail b on a.fID=b.fID
join FoodStuff c on b.sID=c.sID
where c.Name like'%'+@Name+'%'
and Price>=30000;
else if(@Type='*')
select a.Name,Price from Food
a join FoodDetail b on a.fID=b.fID
join FoodStuff c on b.sID=c.sID
where c.Name like'%'+@Name+'%';
end;
--Thử nghiệm:
exec sp_FoodChoice N'Thịt',N'Đắt';
--13.
create trigger tg_NoUpdatePrice on Food
for update as
begin
if(exists(select*from inserted
where Price>=40000))
begin
print N'Giá phải nhỏ hơn 40000';
rollback;
end;
end;
--Thử nghiệm:
update Food set Price=40000;
--14.
alter trigger tg_delFood on Food
instead of delete as
begin
delete from FoodDetail where
fID in(select fID from deleted);
delete from Food where
fID in(select fID from deleted);
print N'Đã xóa dữ liệu thành công!';
end;
--Thử nghiệm:
select*from Food a join FoodDetail b
on a.fID=b.fID;
delete from Food where fID=2;

Solution Practical 1

--2.

create database DBLab1;
use DBLab1;

--3.

create table subjects(
    subjectid int not null,
    subjectname nvarchar(50)
);

create table students(
    studentid int not null,
    studentname nvarchar(50),
    age int,
    email varchar(100)
);

create table classes(
    classid int not null,
    classname nvarchar(50)
);

create table marks(
    mark int,
    subjectid int,
    studentid int
);

create table classstudent(
    studentid int,
    classid int
);

--Thiết lập các ràng buộc:

alter table subjects add constraint pk1 primary key(subjectid);
alter table students add constraint pk2 primary key(studentid);
alter table classes add constraint pk3 primary key(classid);

alter table marks add constraint fk1 foreign key(subjectid) references subjects;
alter table marks add constraint fk2 foreign key(studentid) references students;
alter table classstudent add constraint fk3 foreign key(classid) references classes;
alter table classstudent add constraint fk4 foreign key(studentid) references students;

alter table marks drop constraint fk1;
alter table subjects drop constraint pk1;

insert students values(1,'Nguyen Quang An',18,'an@yahoo.com');
insert students values(2,'Nguyen Cong Vinh',20,'vinh@gmail.com');
insert students values(3,'Nguyen Van Quyen',19,'Quyen');
insert students values(4,'Pham Thanh Binh',25,'binh@com');
insert students values(5,'Nguyen Van Tai Em',30,'taiem@sport.vn');

insert classes values (1,'C0706L'), (2,'C0708G');

insert classstudent values(1,1), (2,1), (3,2), (4,2), (5,2);

--delete from classstudent where studentid=1;

insert subjects values(1,'SQL'), (2,'Java'), (3,'C'), (4,'Visual Basic');

insert marks values(8,1,1);
insert marks values(4,2,1);
insert marks values(9,1,1);
insert marks values(7,1,3);
insert marks values(3,1,4);
insert marks values(5,2,5);
insert marks values(8,3,3);
insert marks values(1,3,5);
insert marks values(3,2,4);

--1.
select * from students order by studentname;

--2.
select * from subjects;

--3.
select * from students where email like '%@%' and email like '%.%';

--4.
select * from students where studentname like 'Nguyen%';

--5.
select studentname,classname from students,classes,classstudent where students.studentid=classstudent.studentid and classstudent.classid=classes.classid and classname='C0706L';

--6.
select studentname,subjectname,mark from students,subjects,marks where students.studentid=marks.studentid and marks.subjectid=subjects.subjectid;

--7.
select studentname from students where studentid not in(select studentid from marks);

--8.
select subjectname from subjects where subjectid not in(select subjectid from marks);

--9.
select studentname, avg(mark) as N'Điểm TB' from students,marks where students.studentid=marks.studentid group by studentname;

--10.
select top 1 subjectname,count(marks.subjectid) from subjects,marks where subjects.subjectid=marks.subjectid group by subjectname order by count(marks.subjectid) desc;

--11.
select subjectname,mark from subjects,marks where subjects.subjectid=marks.subjectid and mark=(select max(mark) from marks);

--12.
select top 1 subjectname,count(mark) from subjects,marks where subjects.subjectid=marks.subjectid and mark<5 group by subjectname order by count(mark) desc;

--13.
alter table students add constraint ck1 check(age>15 and age<50);

--14.
alter table marks drop constraint fk1,fk2;
alter table classstudent drop constraint fk3,fk4;

--15.
delete from students where studentid=1;

--16.
alter table students add status bit default 1;

--17.
update  students set status=0;

Vòng lặp while trong MySQL

Cú pháp

WHILE (điều_kiện) DO
    Khối_lệnh;
END WHILE;

Ví dụ

Vòng lặp while được sử dụng trong store procedure (SP):

DELIMITER $$

DROP PROCEDURE IF EXISTS loopWhile$$

CREATE PROCEDURE loopWhile(
  IN a INT(11),
  IN b INT(11)
)
  BEGIN
    -- Chuoi in ra man hinh--
    DECLARE str  VARCHAR(255) DEFAULT '';

    WHILE (a <= b) DO
      SET  str = CONCAT(str,a,',');
      SET  a = a + 1;
    END WHILE;

    SELECT str;
  END$$
DELIMITER ;

Cách dùng NOT IN trong MySQL

Giả sử có 2 bảng students chứa thông tin học sinh và bảng marks chứa điểm học sinh. Khi đó nếu ta cần lấy những học sinh chưa có điểm thì ta cần dùng NOT IN như sau:

SELECT * FROM students WHERE id NOT IN (SELECT studentId FROM marks)

Biểu thức chính quy trong MySQL

Biểu thức chính quy (Regular Expression) là một cách mạnh mẽ để chỉ định mẫu cho tìm kiếm phức tạp. Phần này thảo luận về các toán tử có sẵn cho khớp biểu thức chính quy và minh họa, với các ví dụ, một số ký tự và cấu trúc đặc biệt có thể được sử dụng cho các hoạt động biểu thức chính quy.

Toán tử biểu thức chính quy

expr NOT REGEXP patexpr NOT RLIKE pat

Điều này giống như  NOT (expr REGEXP pat).

expr REGEXP patexpr RLIKE pat

Trả về 1 nếu chuỗi  expr khớp với biểu thức chính quy được chỉ định bởi mẫu  pat, 0 nếu không. Nếu một trong hai  expr hoặc  pat là  NULL, giá trị trả về là  NULL.

RLIKE là một từ đồng nghĩa với  REGEXP, được cung cấp để  mSQL tương thích.

Mẫu có thể là một biểu thức chính quy mở rộng, cú pháp được thảo luận trong  Cú pháp biểu thức chính quy . Các mẫu không cần phải là một chuỗi chữ. Ví dụ, nó có thể được chỉ định làm biểu thức chuỗi hoặc cột bảng.

Các hoạt động biểu thức chính quy sử dụng bộ ký tự và đối chiếu biểu thức chuỗi và đối số mẫu khi quyết định loại ký tự và thực hiện so sánh. Nếu các đối số có các bộ ký tự hoặc các đối chiếu khác nhau, các quy tắc cưỡng chế sẽ được áp dụng. Nếu một trong hai đối số là một chuỗi nhị phân, thì các đối số được xử lý theo kiểu phân biệt chữ hoa chữ thường dưới dạng chuỗi nhị phân.

mysql> SELECT 'Michael!' REGEXP '.*'; # tìm thấy
mysql> SELECT 'new*\n*line' REGEXP 'new\\*.\\*line'; # không tìm thấy
mysql> SELECT 'a' REGEXP '^[a-d]'; # tìm thấy
mysql> SELECT 'a' REGEXP 'A', 'a' REGEXP BINARY 'A'; không tìm thấy

Cú pháp biểu thức chính quy

Một biểu thức chính quy mô tả một tập hợp các chuỗi. Biểu thức chính quy đơn giản nhất là biểu thức không có ký tự đặc biệt trong đó. Ví dụ, biểu thức chính quy  hello khớp với  hello và không có gì khác.

Các biểu thức chính quy không cần thiết sử dụng một số cấu trúc đặc biệt để chúng có thể khớp với nhiều hơn một chuỗi. Ví dụ, biểu thức chính quy  hello|world chứa toán tử xen kẽ | và khớp với  hello hoặc  world.

Biểu thức chính quy  B[an]*s phù hợp với các chuỗi BananasBaaaaasBs, và bất kỳ chuỗi nào bắt đầu với một  B, kết thúc với một  s, và có chứa bất kỳ số lượng ký tự a hoặc n.

Biểu thức chính quy cho toán tử REGEXP có thể sử dụng bất kỳ ký tự và cấu trúc đặc biệt nào sau đây:

  • ^

Khớp với phần đầu của một chuỗi.

mysql> SELECT 'fo\nfo' REGEXP '^fo$'; #khớp
mysql> SELECT 'fofo' REGEXP '^fo'; #không khớp
  • $

Nối phần cuối của chuỗi.

mysql> SELECT 'fo\no' REGEXP '^fo\no$'; #khớp
mysql> SELECT 'fo\no' REGEXP '^fo$'; #không khớp
  • .

Ứng với 1 ký tự bất kỳ.

mysql> SELECT 'fofo' REGEXP '^f.*$'; #khớp
mysql> SELECT 'fo\r\nfo' REGEXP '^f.*$'; #khớp
  • a*

Ứng với có từ 0 ký tự a.

mysql> SELECT 'Ban' REGEXP '^Ba*n'; #khớp
mysql> SELECT 'Baaan' REGEXP '^Ba*n'; #khớp
mysql> SELECT 'Bn' REGEXP '^Ba*n'; #khớp
  • a+

Ứng với có từ 1 ký tự a.

mysql> SELECT 'Ban' REGEXP '^Ba+n'; #khớp
mysql> SELECT 'Bn' REGEXP '^Ba+n'; #không khớp
  • a?

Ứng với có 0 hoặc 1 ký tự a.

mysql> SELECT 'Bn' REGEXP '^Ba?n'; #khớp
mysql> SELECT 'Ban' REGEXP '^Ba?n'; #khớp
mysql> SELECT 'Baan' REGEXP '^Ba?n'; #không khớp
  • de|abc

Ứng với có de hoặc abc.

mysql> SELECT 'pi' REGEXP 'pi|apa'; #khớp
mysql> SELECT 'axe' REGEXP 'pi|apa'; #không khớp
mysql> SELECT 'apa' REGEXP 'pi|apa'; #khớp
mysql> SELECT 'apa' REGEXP '^(pi|apa)$'; #khớp
mysql> SELECT 'pi' REGEXP '^(pi|apa)$'; #khớp
mysql> SELECT 'pix' REGEXP '^(pi|apa)$'; #không khớp
  • (abc)*

Ứng với có từ 0 chuỗi abc.

mysql> SELECT 'pi' REGEXP '^(pi)*$'; #khớp
mysql> SELECT 'pip' REGEXP '^(pi)*$'; #không khớp
mysql> SELECT 'pipi' REGEXP '^(pi)*$'; #khớp
  • {m}{m,n}

Ứng với có từ m ký tự, hoặc có từ m đến n ký tự. Các trường hợp cụ thể:

  • a{2}

Ứng với có từ 2 ký tự a

  • a{2,10}

Ứng với có từ 2 đến 10 ký tự a.

  • a*

Có thể viết là  a{0,}.

  • a+

Có thể viết là  a{1,}.

  • a?

Có thể viết là  a{0,1}.

m và  n thường phải nằm trong phạm vi từ 0 đến 255. Các ví dụ:

mysql> SELECT 'abcde' REGEXP 'a[bcd]{2}e'; #không khớp
mysql> SELECT 'abcde' REGEXP 'a[bcd]{3}e'; #khớp
mysql> SELECT 'abcde' REGEXP 'a[bcd]{1,10}e'; #khớp
  • [a-dX][^a-dX]

Phù hợp với bất kỳ ký tự đó là (hoặc không, nếu  ^ được sử dụng) hoặc  abcd hoặc  X. Một ký tự - nằm giữa hai ký tự khác tạo thành một phạm vi khớp với tất cả các ký tự từ ký tự đầu tiên đến ký tự thứ hai. Ví dụ,  [0-9] phù hợp với bất kỳ chữ số thập phân.

mysql> SELECT 'aXbc' REGEXP '[a-dXYZ]'; #khớp
mysql> SELECT 'aXbc' REGEXP '^[a-dXYZ]$'; #không khớp
mysql> SELECT 'aXbc' REGEXP '^[a-dXYZ]+$'; #không khớp
mysql> SELECT 'aXbc' REGEXP '^[^a-dXYZ]+$'; #không khớp
mysql> SELECT 'gheis' REGEXP '^[^a-dXYZ]+$'; #khớp
mysql> SELECT 'gheisa' REGEXP '^[^a-dXYZ]+$'; #khớp
  • [.characters.]

Trong một biểu thức ngoặc (viết bằng cách sử dụng [ và ]), khớp với chuỗi ký tự của phần tử đối chiếu đó. characters là một ký tự đơn hoặc một ký tự tương ứng newline. Bảng sau liệt kê các ký tự được phép.

Bảng sau đây cho thấy tên nhân vật được phép và các ký tự mà chúng khớp. Đối với các ký tự được đưa ra dưới dạng giá trị số, các giá trị được biểu thị bằng số bát phân.

Tên Ký tự Tên Ký tự
NUL 0 SOH 001
STX 002 ETX 003
EOT 004 ENQ 005
ACK 006 BEL 007
alert 007 BS 010
backspace '\b' HT 011
tab '\t' LF 012
newline '\n' VT 013
vertical-tab '\v' FF 014
form-feed '\f' CR 015
carriage-return '\r' SO 016
SI 017 DLE 020
DC1 021 DC2 022
DC3 023 DC4 024
NAK 025 SYN 026
ETB 027 CAN 030
EM 031 SUB 032
ESC 033 IS4 034
FS 034 IS3 035
GS 035 IS2 036
RS 036 IS1 037
US 037 space ' '
exclamation-mark '!' quotation-mark '"'
number-sign '#' dollar-sign '$'
percent-sign '%' ampersand '&'
apostrophe '\'' left-parenthesis '('
right-parenthesis ')' asterisk '*'
plus-sign '+' comma ','
hyphen '-' hyphen-minus '-'
period '.' full-stop '.'
slash '/' solidus '/'
zero '0' one '1'
two '2' three '3'
four '4' five '5'
six '6' seven '7'
eight '8' nine '9'
colon ':' semicolon ';'
less-than-sign '<' equals-sign '='
greater-than-sign '>' question-mark '?'
commercial-at '@' left-square-bracket '['
backslash '\\' reverse-solidus '\\'
right-square-bracket ']' circumflex '^'
circumflex-accent '^' underscore '_'
low-line '_' grave-accent '`'
left-brace '{' left-curly-bracket '{'
vertical-line '|' right-brace '}'
right-curly-bracket '}' tilde '~'
DEL 177    
Ví dụ:
mysql> SELECT '~' REGEXP '[[.~.]]'; #khớp
mysql> SELECT '~' REGEXP '[[.tilde.]]'; #khớp
  • [=character_class=]

Trong một biểu thức ngoặc (=[ và ]),  [=character_class=] đại diện cho một lớp tương đương. Nó phù hợp với tất cả các ký tự có cùng giá trị đối chiếu, bao gồm cả chính nó. Ví dụ, nếu  o và  (+) là những thành viên của một lớp tương đương, thì [[=o=]][[=(+)=]], và [o(+)] tất cả đều tương đương. Một lớp tương đương có thể không được sử dụng làm điểm cuối của một phạm vi.

  • [:character_class:]

Trong một biểu thức ngoặc ([ và ]), [:character_class:] đại diện cho một lớp ký tự khớp với tất cả các ký tự thuộc lớp đó. Bảng sau liệt kê các tên lớp tiêu chuẩn. Mỗi miền địa phương cụ thể có thể cung cấp tên lớp khác. Một lớp ký tự có thể không được sử dụng làm điểm cuối của một phạm vi.

Tên lớp ký tự Ý nghĩa
alnum Ký tự chữ và số
alpha Ký tự chữ cái
blank Ký tự khoảng trắng
cntrl Điều khiển nhân vật
digit Chữ số ký tự
graph Nhân vật đồ họa
lower Chữ cái viết thường
print Nhân vật đồ họa hoặc không gian
punct Ký tự dấu chấm câu
space Không gian, tab, dòng mới, và vận chuyển trở lại
upper Ký tự chữ cái in hoa
xdigit Ký tự chữ số thập lục phân
Ví dụ:
mysql> SELECT 'justalnums' REGEXP '[[:alnum:]]+'; #khớp
mysql> SELECT '!!' REGEXP '[[:alnum:]]+'; #không khớp
  • [[:<:]][[:>:]]

Những điểm đánh dấu là viết tắt của ranh giới từ. Chúng phù hợp với đầu và cuối của từ tương ứng. Một từ là một chuỗi các ký tự từ không được theo trước hoặc theo sau bởi các ký tự từ. Một ký tự từ là một ký tự chữ và số trong lớp  alnum hoặc dấu gạch dưới ( _).

mysql> SELECT 'a word a' REGEXP '[[:<:]]word[[:>:]]'; #khớp
mysql> SELECT 'a xword a' REGEXP '[[:<:]]word[[:>:]]'; #không khớp

Nếu muốn chuyển ký tự đặc biệt của biểu thức chính quy thành ký tự thường thì ta đặt trước ký tự đặc biệt đó 2 dấu gạch chéo ngược (\). Ví dụ, để khớp với chuỗi 1+2, chỉ có biểu thức chính quy cuối cùng sau đây là phù hợp:

mysql> SELECT '1+2' REGEXP '1+2'; #không khớp
mysql> SELECT '1+2' REGEXP '1\+2'; #không khớp
mysql> SELECT '1+2' REGEXP '1\\+2'; #khớp