2012-12-12 37 views
5

Tôi có các thực thể tự phụ thuộc (a) trong cơ sở dữ liệu của tôi, được tham chiếu từ một thực thể khác (b), và cho một thực thể cụ thể (b), tôi cần có tất cả (a) các thực thể cần thiết. Đây là rất nhiều ánh xạ, vì vậy tôi có một bảng ánh xạ riêng. Tôi nghĩ chọn đệ quy Chọn CTE là đặt cược tốt nhất của tôi, nhưng tôi đang gặp sự cố:T-SQL đệ quy Chọn phụ thuộc thông tư

This Fiddle minh họa sự cố của tôi. Nếu một số người dùng giới thiệu một tham chiếu vòng tròn, lựa chọn đệ quy của tôi sẽ bị ngừng lại. Tôi đã được bộ não của tôi để cố gắng tìm cách để sửa lỗi này. Cần lưu ý rằng mặc dù tôi đã giới thiệu Foreign Keys trong fiddle, các khóa ngoại không thực sự được vinh danh bởi hệ thống tôi đang sử dụng (đối số lâu dài với DBAs) - tôi đã giới thiệu chúng để làm cho luồng dữ liệu rõ ràng hơn.

Các truy vấn đệ quy, đối với những người không muốn nhấp chuột đến fiddle:

WITH recur(objID) AS (
    SELECT usesObjID 
     FROM #otherObj 
     WHERE otherObjID = 1 
    UNION ALL 
    SELECT slaveObjID 
     FROM #objMap 
      INNER JOIN recur 
       on #objMap.masterObjID = recur.objID 
)SELECT objID from recur 

Bất kỳ ý tưởng ra khỏi đó? Thiết kế này không được sản xuất, vì vậy tôi có thể thay đổi lược đồ một chút, nhưng tôi không muốn dựa vào việc khám phá các tham chiếu vòng tròn khi chèn, trừ khi nó có thể được thực hiện bởi T-SQL.

+0

bao giờ sử dụng fxn này, nhưng bạn sẽ không chỉ nói 'trên objMap.masterObjID = recur.objID và recur.objID <> # otherobj.usesObjID'? hoặc là ngoài phạm vi? – Beth

Trả lời

8

Có thể đặt MAXRECURSION của CTE, điều này sẽ ngăn vòng lặp vô hạn nhưng bạn vẫn nhận được kết quả lạ vì truy vấn sẽ tiếp tục chạy trong vòng lặp cho đến khi lần truy cập tối đa được nhấn.

Thách thức là vòng lặp liên quan đến nhiều bước, vì vậy bạn không thể chỉ kiểm tra cha mẹ trực tiếp của trẻ để xác định xem bạn có đang trong vòng lặp hay không.

Một cách để xử lý việc này là thêm cột bổ sung vào CTE ... cột mới này, tree, theo dõi tất cả các ID đã được bao gồm cho đến nay và dừng khi ID lặp lại.

WITH recur(objID, Tree) AS (
    SELECT 
     usesObjID, 
     CAST(',' + CAST(usesObjID AS VARCHAR) + ',' AS VARCHAR) AS Tree 
    FROM otherObj 
    WHERE otherObjID = 1 
    UNION ALL 
    SELECT 
     slaveObjID, 
     CAST(recur.Tree + CAST(slaveObjID AS VARCHAR) + ',' AS VARCHAR) AS Tree 
    FROM objMap 
     INNER JOIN recur 
      ON objMap.masterObjID = recur.objID 
    WHERE recur.Tree NOT LIKE '%,' + CAST(slaveObjID AS VARCHAR) + ',%' 
)SELECT objID from recur 

Sql Fiddle Link

+0

Điều này thật tuyệt! Bạn có nghĩ rằng điều này sẽ làm việc tốt nếu nó là một nhiều nhiều bản đồ từ otherObj để Obj? (Cần phải có một bảng lập bản đồ khác) – FrankieTheKneeMan

+0

@FrankieTheKneeMan Tôi nghĩ rằng nó cũng sẽ hoạt động. Về cơ bản bạn vẫn chỉ đang theo dõi các ID mà bạn đã tham gia cho đến nay và dừng lại khi bạn thấy một bản sao. –

+0

http://sqlfiddle.com/#!3/c1e62/3 <- Tôi không tin tưởng Người dùng. Nếu họ hoàn toàn nhấc lên cấu trúc, tôi có thể nhận được kết quả này. Tôi có thể sử dụng một khác biệt để có được giá trị khác biệt (bắt đầu anyway), nhưng có cách nào tốt hơn để làm điều đó? – FrankieTheKneeMan

Các vấn đề liên quan