Ôn lại lý thuyết:
BREAK:
- Dùng để thoát khỏi vòng lặp (BREAK không có bất kỳ đối số nào đi kèm)
- Nếu có nhiều WHILE lồng nhau thì BREAK sẽ thoát vòng lặp WHILE gần nó nhất
- Bỏ qua khối lệnh sau nó (khối lệnh trong bước lặp hiện tại), và thực hiện bước lặp tiếp theo
- CONTINUE không có bất kỳ đối số nào đi kèm
NỘI DUNG: Tìm về vòng lặp WHILE, TRY ... CATCH, RAISERROR
Bài 1:
Dùng vòng WHILE để viết chương trình đơn giản theo yêu cầu:
- Viết chương trình tính tổng các số chẵn từ 1 tới 10.
- Viết chương trình tính tổng các số chẵn từ 1 tới 10 nhưng bỏ số 4.
Bài 2:
Sử dụng cơ sở dữ liệu QLDA. Thực hiện các câu truy vấn sau, sử dụng vòng lặp
- Cho biết thông tin nhân viên (HONV, TENLOT, TENNV) có MaNV là số chẵn.
- Cho biết thông tin nhân viên (HONV, TENLOT, TENNV) có MaNV là số chẵn nhưng không tính nhân viên có MaNV là 4.
- Nhận thông báo “Thêm dữ liệu thành công” từ khối Try
- Chèn sai kiểu dữ liệu cột MaPHG để nhận thông báo lỗi “Thêm dữ liệu thất bại” từ khối Catch
THỰC HIỆN:
Bài 1:
Dùng vòng WHILE để viết chương trình đơn giản theo yêu cầu:
- Viết chương trình tính tổng các số chẵn từ 1 tới 10.
-- Viết chương trình tính tổng các số chẵn từ 1 tới 10
DECLARE @tong INT = 0;
DECLARE @i INT = 1;
WHILE (@i <= 10)
BEGIN
IF(@i % 2 = 0)
SET @tong = @tong + @i
SET @i = @i + 1
END
PRINT @tong
/*
Kết quả là 30 vì:
2
2 + 4 = 6
6 + 6 = 12
12 + 8 = 20
20 + 10 = 30
*/
- Viết chương trình tính tổng các số chẵn từ 1 tới 10, nếu số chẵn là số 8 thì kết thúc chương trình
-- Viết chương trình tính tổng các số chẵn từ 1 tới 10, nếu số chẵn là số 8 thì kết thúc chương trình
DECLARE @tong_break INT = 0;
DECLARE @k INT = 1;
WHILE (@k <= 10)
BEGIN
IF @k = 8
BREAK
IF(@k % 2 = 0)
SET @tong_break = @tong_break + @k
SET @k = @k + 1
END
PRINT @tong_break
/*
Kết quả là 12 vì:
2
2 + 4 = 6
6 + 6 = 12
Khi k = 8 thì BREAK có nghĩa sẽ kết thúc vòng lặp (vòng lặp gần nó nhất)
*/
DECLARE @tong_break INT = 0;
DECLARE @k INT = 1;
WHILE (@k <= 10)
BEGIN
IF(@k % 2 = 0)
IF @k = 8
BREAK
ELSE
SET @tong_break = @tong_break + @k
SET @k = @k + 1
END
PRINT @tong_break
- Viết chương trình tính tổng các số chẵn từ 1 tới 10 nhưng bỏ số 4.
-- Viết chương trình tính tổng các số chẵn từ 1 tới 10 nhưng bỏ số 4.
DECLARE @tong_bo4 INT = 0;
DECLARE @j INT = 1;
WHILE (@j <= 10)
BEGIN
IF @j = 4
BEGIN
SET @j = @j + 1 -- phải tăng lên đếm lên 1, nếu không sẽ bị lặp vô hạng do biến đếm j = 4 hoài -> lặp tô tận
CONTINUE;
END
IF (@j % 2= 0)
SET @tong_bo4= @tong_bo4 + @j
SET @j = @j + 1
END
PRINT @tong_bo4
/*
Kết quả là 26 vì:
Cách hoạt động cũng tương tự như tính tổng, tuy nhiên khi @j = 4, nó tăng lên 1 đơn vị và KHÔNG thực hiện phép cộng với giá trị = 4 này
*/
Bài 2:
Sử dụng cơ sở dữ liệu QLDA. Thực hiện các câu truy vấn sau, sử dụng vòng lặp
Cho biết thông tin nhân viên (HONV, TENLOT, TENNV) có MaNV là số chẵn.
Lấy thông tin và sắp xếp MANV theo thứ tự giảm dần
-- Lấy thông tin và sắp xếp MANV theo thứ tự giảm dần
SELECT MANV
FROM NHANVIEN
ORDER BY MANV DESC;
Để đảm bảo MANV là INT thì chúng ta nên ép kiểu MANV sang INT, và lấy ra MANV cao nhất
-- Để đảm bảo MANV là INT thì chúng ta nên ép kiểu MANV sang INT, và lấy ra MANV cao nhất
SELECT TOP 1
CONVERT(INT, MANV)
FROM NHANVIEN
ORDER BY CONVERT(INT, MANV) DESC
Lấy MANV cao nhất gán vào biến @max_manv, và MANV nhấp nhất gán vào biến @min_manv (1)
-- Lấy MANV cao nhất gán vào biến @max_manv
DECLARE @max_manv INT
SET @max_manv = (SELECT TOP 1
CONVERT(INT, MANV)
FROM NHANVIEN
ORDER BY CONVERT(INT, MANV) DESC
)
-- Tương tự lấy MANV nhấp nhất gán vào biến @min_manv
DECLARE @min_manv INT
SET @min_manv = (SELECT TOP 1
CONVERT(INT, MANV)
FROM NHANVIEN
ORDER BY CONVERT(INT, MANV) ASC
)
-- HOẶC
DECLARE @min int = (select min(CAST(manv as int)) from NHANVIEN);
DECLARE @max int = (select max(CAST(manv as int)) from NHANVIEN);
Thực hiện theo yêu cầu (phải kết hợp với (1) để chạy nhé các bạn)
-- Thực hiện theo yêu cầu
WHILE (@min_manv < @max_manv)
BEGIN
IF (@min_manv % 2 = 0)
BEGIN
SELECT MANV
, HONV, TENLOT, TENNV
FROM NHANVIEN
WHERE CONVERT(INT, MANV) = @min_manv
END
SET @min_manv = @min_manv + 1
END
Noted 1: Với kiểu thực hiện vòng lặp như code trên chương trình chạy có nhiều khi xuất ra các dòng trắng vì MANV không tồn tại trong trường hợp MANV không liên tục,...
Để khắc phục lỗi đó chúng ta có thể kiểm tra xem @min_manv có tồn trong bảng NHANVIEN thì mới thực hiện
-- Để khắc phục lỗi đó chúng ta có thể kiểm tra xem @min_manv có tồn trong bảng NHANVIEN thì mới thực hiện
WHILE (@min_manv < @max_manv)
BEGIN
IF (@min_manv % 2 = 0)
BEGIN
IF EXISTS(SELECT CONVERT(INT, MANV) FROM NHANVIEN WHERE CONVERT(INT, MANV) = @min_manv) -- kiểm tra sự tồn tại của @min_manv trong bảng NHANVIEN
SELECT MANV
, HONV, TENLOT, TENNV
FROM NHANVIEN
WHERE (CONVERT(INT, MANV) = @min_manv)
END
SET @min_manv = @min_manv + 1
END;
Noted 2: Hai số chẵn kế nhau cách nhau 2 đơn vị, nếu chúng ta đã xác định được số đầu tiên rồi để tìm số chẵn tiếp theo thì chúng ta lấy số đó cộng thêm 2. => Với code trên các bạn xem và thay đổi sao cho hợp lý nhất để chương trình không cần kiểm tra các @min_manv là số lẻ. Như vậy lúc này vòng lặp chúng ta sẽ thực hiện lặp ít hơn,... mà vẫn cho ra kết quả không đổi.
Tham khảo cách KHÔNG DÙNG vòng lặp:
khong dung vong lap
SELECT MANV, TENLOT, TENNV
FROM NHANVIEN
WHERE CONVERT(INT,MANV) %2 = 0
Cho biết thông tin nhân viên (HONV, TENLOT, TENNV) có MaNV là số chẵn nhưng không tính nhân viên có MaNV là 4.
-- Cho biết thông tin nhân viên (HONV, TENLOT, TENNV) có MaNV là số chẵn nhưng không tính nhân viên có MaNV là 4
WHILE (@min_manv < @max_manv)
BEGIN
IF (@min_manv = 4)
BEGIN
SET @min_manv = @min_manv + 1
CONTINUE
END
IF (@min_manv % 2 = 0)
BEGIN
IF EXISTS(SELECT CONVERT(INT, MANV) FROM NHANVIEN WHERE CONVERT(INT, MANV) = @min_manv) -- kiểm tra sự tồn tại của @min_manv trong bảng NHANVIEN
SELECT MANV
, HONV, TENLOT, TENNV
FROM NHANVIEN
WHERE (CONVERT(INT, MANV) = @min_manv)
END
SET @min_manv = @min_manv + 1
END;
-- HOẶC
WHILE (@min_manv < @max_manv)
BEGIN
IF (@min_manv % 2 = 0)
IF @min_manv = 4
BEGIN
SET @min_manv = @min_manv + 1
CONTINUE
END
ELSE
BEGIN
IF EXISTS(SELECT CONVERT(INT, MANV) FROM NHANVIEN WHERE CONVERT(INT, MANV) = @min_manv) -- kiểm tra sự tồn tại của @min_manv trong bảng NHANVIEN
SELECT MANV
, HONV, TENLOT, TENNV
FROM NHANVIEN
WHERE (CONVERT(INT, MANV) = @min_manv)
END
SET @min_manv = @min_manv + 1
END;
Noted: Các bạn xem xem 2 cách trên, cách nào tối ưu hơn, vì sao
- Nhận thông báo “Thêm dữ liệu thành công” từ khối Try
- Chèn sai kiểu dữ liệu cột MaPHG để nhận thông báo lỗi “Thêm dữ liệu thất bại” từ khối Catch
BEGIN TRY
INSERT PHONGBAN ([TENPHG]
,[MAPHG]
,[TRPHG]
,[NG_NHANCHUC])
VALUES ('keToan',2,'003','2020-06-02')
-- Nếu lệnh chèn thực thi thành công in ra dòng bên dưới
PRINT 'SUCCESS: Them du lieu THANH CONG'
END TRY
-- Nếu có lỗi xảy ra khi chèn dữ liệu in ra dòng thông báo lỗi cùng với thông tin mã lỗi và thông báo lỗi
BEGIN CATCH
PRINT 'FAILURE: Them du lieu THAT BAI'
PRINT 'ERROR ' + CONVERT(varchar, ERROR_NUMBER())
+ ': ' + ERROR_MESSAGE()
END CATCH
(1 row affected)SUCCESS: Them du lieu THANH CONGCompletion time: 2022-05-25T10:50:40.1103666+07:00
(0 rows affected)FAILURE: Them du lieu THAT BAIERROR 2627: Violation of PRIMARY KEY constraint 'PK_PhongBan'. Cannot insert duplicate key in object 'dbo.PHONGBAN'. The duplicate key value is (3).Completion time: 2022-05-25T10:51:03.3769594+07:00
BEGIN TRY
DECLARE @chia INT
SET @chia = 55/0
END TRY
BEGIN CATCH
DECLARE
@ErrMessage NVARCHAR(2048), -- độ dài của chuỗi thông báo lỗi
@ErrSeverity INT,
@ErrState INT
SELECT
@ErrMessage = ERROR_MESSAGE(),
@ErrSeverity = ERROR_SEVERITY(),
@ErrState = ERROR_STATE()
RAISERROR(@ErrMessage, @ErrSeverity, @ErrState) -- thực hiện hiển thị thông báo
END CATCH
Kết quả:
Msg 50000, Level 16, State 1, Line 15
Divide by zero error encountered.
Completion time: 2022-05-25T11:10:58.7629608+07:00
Xong!