Được gửi bởi
tinhtoi
Có hai trường hợp:
1.Nếu không có map: bạn không thể xác định một nhánh trong cây mà phải lấy ra cả cây => dư thừa.
2.Có map: khi cập nhật phải xác định map cho một nhánh, mà cái này cũng phải dùng đệ quy để xác định => rắc rối như khi search. Trường hợp kết chuyển nhiều thứ thì cập nhật dữ liệu sẽ rất chậm.
Mình không rành về store lắm nên không viết được T-SQL, bạn thông cảm. mình xử lý bằng code.
[=========> Bổ sung bài viết <=========]
Hàm đệ quy nè bạn:
Sub layNVTheoNode(ByVal NhanVienID As String, ByVal arr As ArrayList)
arr.Add(NhanVienID )
Dim ds As New DataSet
If Lay_SQL_P(ds, "select NhanVienID from NhanVien where NhanVienCha=@NhanVienCha", NhanVienID ) = True Then
If ds.Tables(0).Rows.Count > 0 Then
For Each drw As DataRow In ds.Tables(0).Rows
layNVTheoNode(drw("NhanVienID").ToString, arr)
Next
End If
End If
End Sub
[=========> Bổ sung bài viết <=========]
Nói chung mình thấy chưa được hay lắm
Vấn đề là mỗi lần hàm đệ quy trên được gọi, nó kết nối với CSDL để lấy về danh sách của những nhân viên dưới quyền. Như thế, hàm đệ quy có thể phải truy vấn CSDL cả hàng trăm, hàng ngàn lần tùy theo kích thước và mức độ phân quyền. Thành thử ra, dở là cái chắc.
Hôm nay đã khuya. Thôi hẹn ngày mai tôi sẽ đưa lên cách dùng giải thuật đệ quy trong CSDL để giải quyết vấn đề bạn đã đưa ra.
**** Tiếp tục..
Đệ quy là danh từ được dịch qua tiếng Việt từ chữ recursive, có nghĩa là một vòng tự lặp.
Khi thiết kế một CSDL, đôi khi các bạn sẽ có nhu cầu cần phải tạo lên một bảng đệ quy. Bảng đệ quy là một bảng có khoá ngoại liên kết với khoá chính của chính nó, thí dụ như bảng NHAN_VIEN dưới đây, có khoá ngoại cho ma_truong_nhom liên kết với ma_nhan_vien:
Code:
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[NHAN_VIEN]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
CREATE TABLE dbo.NHAN_VIEN
(
ma_nhan_vien UNIQUEIDENTIFIER NOT NULL DEFAULT(NEWID()),
ma_truong_nhom UNIQUEIDENTIFIER NULL,
ma_chuc_vu UNIQUEIDENTIFIER NOT NULL,
ma_luong UNIQUEIDENTIFIER NOT NULL,
CONSTRAINT PK_NHAN_VIEN PRIMARY KEY
(
ma_nhan_vien
),
CONSTRAINT FK_NHAN_VIEN_ma_truong_nhom FOREIGN KEY
(
ma_truong_nhom
)REFERENCES [dbo].[NHAN_VIEN](ma_nhan_vien) -- Recursive (tự liên kết)
)
END
GO
Khi các bạn đã có một bảng đệ quy rồi, thì việc dùng Bảng Giải thuật Thông dụng (Common Table Expression - CTE) để truy vấn và lấy về một tập hợp dữ liệu được phân cấp rất dễ dàng. Xin lưu ý là với Bảng Giải thuật Thông Dụng (BGT), các bạn không cần phải có một bảng đệ quy mà vẫn có thể truy vấn và lấy về một tập hợp dữ liệu được phân cấp.
Dưới đây là stored procedure isp_truy_van_nhan_vien:
Code:
IF EXISTS(SELECT 1 FROM sysobjects WHERE id = OBJECT_ID('dbo.isp_truy_van_nhan_vien')
AND OBJECTPROPERTY(id,N'IsProcedure') = 1
)
BEGIN
DROP PROCEDURE dbo.isp_truy_van_nhan_vien
END
GO
CREATE PROC dbo.isp_truy_van_nhan_vien
--WITH ENCRYPTION
AS
BEGIN
SET NOCOUNT ON
WITH CTE_NHAN_VIEN (ma_nhan_vien,ma_truong_nhom,ma_chuc_vu,ma_luong, phan_cap) AS
(
-- truy vấn cấp cao nhất
SELECT
ma_nhan_vien,
ma_truong_nhom,
ma_chuc_vu,
ma_luong,
1 as phan_cap
FROM NHAN_VIEN(NOLOCK)
WHERE ma_truong_nhom IS NULL
UNION ALL
-- vòng lặp đệ quy
SELECT
NV.ma_nhan_vien,
NV.ma_truong_nhom,
NV.ma_chuc_vu,
NV.ma_luong,
CTE.phan_cap + 1 as phan_cap
FROM NHAN_VIEN NV (NOLOCK)
INNER JOIN CTE_NHAN_VIEN CTE
ON(CTE.ma_nhan_vien = NV.ma_truong_nhom)
)
-- Và sau cùng, lấy về tất cả những bản ghi đã được đưa vào bảng biểu thức thông dụng
SELECT *
FROM CTE_NHAN_VIEN
ORDER BY phan_cap
END
GO
Với stored procedure trên, các bạn chỉ cần truy vấn từ CSDL một lần duy nhất là có một tập hợp những bản ghi của nhân viên được phân cấp.
Tưởng cũng nên nói thêm rằng, BGT không phải chỉ dành riêng cho đệ quy, mà chỉ là một công cụ rất tốt cho đệ quy. Các bạn có thể dùng BGT trong bất cứ một trường hợp nào cần dùng đến bảng nhớ tạm thời (MEMORY TABLE).
Bookmarks