2013-11-01 13 views
6

Tôi có bốn bảng, TopLevelParent, hai bảng ở giữa MidParentA và MidParentB và bảng con có thể có cha hoặc mẹ của MidParentA hoặc MidParentB (Một hoặc midParent khác phải ở trong địa điểm). Cả hai bảng ở giữa đều có một bảng cha của TopLevelParent.Máy chủ SQL còn lại tham gia với toán tử 'Hoặc'

Top Cấp bảng nhìn như thế này:

TopLevelId | Name 
-------------------------- 
1   | name1 
2   | name2 

Các bảng MidParent trông như thế này:

MidParentAId | TopLevelParentId |   MidParentBId | TopLevelParentId | 
------------------------------------  ------------------------------------ 
1   |  1   |   1   |  1   | 
2   |  1   |   2   |  1   | 

Bảng Child giống như thế này:

ChildId | MidParentAId | MidParentBId 
-------------------------------- 
1  |  1  | NULL 
2  | NULL  |  2 

Tôi đã sử dụng bên trái sau đây tham gia vào một thủ tục được lưu trữ lớn hơn mà là thời gian ra, và nó trông giống như HOẶC operato r vào cuối cùng bên trái tham gia là thủ phạm:

SELECT *  
FROM TopLevelParent tlp 
LEFT JOIN MidParentA a ON tlp.TopLevelPatientId = a.TopLevelPatientId 
LEFT JOIN MidParentB a ON tlp.TopLevelPatientId = b.TopLevelPatientId 
LEFT JOIN Child c ON c.ParentAId = a.ParentAId OR c.ParentBId = b.ParentBId 

Có cách nào hiệu quả hơn để thực hiện việc này không?

Trả lời

2

Dưới đây là những gì tôi đã làm cuối cùng, thời gian thực hiện giảm từ 52 giây xuống còn 4 giây.

SELECT * 
FROM (
    SELECT tpl.*, a.MidParentAId as 'MidParentId', 1 as 'IsMidParentA' 
    FROM TopLevelParent tpl 
    INNER JOIN MidParentA a ON a.TopLevelParentId = tpl.TopLevelParentID 
UNION 
    SELECT tpl.*, b.MidParentBId as 'MidParentId', 0 as 'IsMidParentA' 
    FROM TopLevelParent tpl 
    INNER JOIN MidParentB b ON b.TopLevelParentId = tpl.TopLevelParentID 
UNION 
    SELECT tpl.*, 0 as 'MidParentId', 0 as 'IsMidParentA' 
    FROM TopLevelParent tpl 
    WHERE tpl.TopLevelParentID NOT IN (
     SELECT pa.TopLevelParentID 
     FROM TopLevelParent tpl 
     INNER JOIN MidParentA a ON a.TopLevelParentId = tpl.TopLevelParentID 
    UNION 
     SELECT pa.TopLevelParentID 
     FROM TopLevelParent tpl 
     INNER JOIN MidParentB b ON h.TopLevelParentId = tpl.TopLevelParentID 
    ) 
) tpl 
LEFT JOIN MidParentA a ON a.TopLevelParentId = tpl.TopLevelParentID 
LEFT JOIN MidParentB b ON b.TopLevelParentId = tpl.TopLevelParentID 
LEFT JOIN 
(
     SELECT [ChildId] 
       ,[MidParentAId] as 'MidParentId' 
       ,1 as 'IsMidParentA' 
     FROM Child c 
     WHERE c.MidParentAId IS NOT NULL 
    UNION 
     SELECT [ChildId] 
       ,[MidParentBId] as 'MidParentId' 
       ,0 as 'IsMidParentA' 
     FROM Child c 
     WHERE c.MidParentBId IS NOT NULL 
) AS c 
ON c.MidParentId = tpl.MidParentId AND c.IsMidParentA = tpl.IsMidParentA 

này giúp loại bỏ các bảng quét rằng đã xảy ra, như tôi đã xuất hiện kỷ lục cấp cao nhất để cha mẹ midlevel nó lên phía trước nếu nó tồn tại, và đóng dấu nó trong lịch sử đó.

Tôi cũng đã thực hiện tương tự với bản ghi con nghĩa là tôi chỉ có thể tham gia bản ghi con vào bản ghi mức cao nhất trên MidParentId và tôi sử dụng cờ bit IsMidParentA để phân biệt nơi có hai MidParentIds giống nhau Id của 1 cho IsMidParentA và IsMidParentB).

Nhờ tất cả những người dành thời gian để trả lời.

+3

Đây là một số kinh doanh phức tạp – Roel

2

Bạn nên sử dụng các vị từ bên trong Bật.

"Điều quan trọng là phải hiểu rằng, với các kết nối bên ngoài, các mệnh đề ON và WHERE đóng vai trò rất khác nhau, và do đó, chúng không thể hoán đổi cho nhau. Mệnh đề WHERE vẫn đóng một vai trò lọc đơn giản - cụ thể là nó giữ sử dụng một cái gì đó như thế này và sử dụng các vị từ trong mệnh đề where.Tuy nhiên, mệnh đề ON không đóng một vai trò lọc đơn giản, thay vào đó, nó là một vai trò phù hợp hơn. Nói cách khác, một hàng trong bên được bảo tồn sẽ được trả về cho dù biến vị ngữ ON tìm thấy một kết quả phù hợp cho nó hay không. Vì vậy, biến vị ngữ ON chỉ xác định những hàng nào từ bên không được bảo vệ sẽ được đối sánh với các hàng từ bên được bảo quản — không phải trả về các hàng từ bên được bảo tồn hay không. " ** Bài kiểm tra 70-461: Truy vấn Microsoft SQL Server 2012

9

Cho biết ít truy vấn đang được hiển thị; một nguyên tắc rất thô là thay thế một hoặc bằng một liên minh để tránh quét bảng.

Select.. 
LEFT JOIN Child c ON c.ParentAId = a.ParentAId 
union 
Select.. 
left Join Child c ON c.ParentBId = b.ParentBId 
+0

Tôi đã chỉnh sửa câu hỏi để hiển thị thêm truy vấn –

+1

Điều đó giúp :) Bạn có thể có hai lần kết nối với Trẻ em thay vì mỗi lần tham gia một bên của OR; và sau đó sử dụng coalesce để có được một giá trị từ C hoặc D, nơi bạn chỉ muốn có một giá trị – u07ch

0

một cách khác để viết nó:

LEFT JOIN Child c ON c.ParentAId = COALESCE(a.ParentAId, b.ParentBId)

Sửa

Một cách tiếp cận có thể được truy vấn đầu tiên MidParentA và sau đó là MidParentB và sau đó UNION kết quả:

SELECT tlp.*, 
     a.MidParentAId, 
     null MidParentBId, 
     c.ChildId 
FROM TopLevelParent tlp 
LEFT JOIN MidParentA a ON tlp.TopLevelPatientId = a.TopLevelPatientId 
LEFT JOIN Child c ON c.MidParentAId = a.MidParentAId 
UNION 
SELECT tlp.*, 
     null MidParentAId, 
     b.MidParentBId, 
     c.ChildId 
FROM TopLevelParent tlp 
LEFT JOIN MidParentB b ON tlp.TopLevelPatientId = b.TopLevelPatientId 
LEFT JOIN Child c ON c.MidParentBId = b.MidParentBId 

Bản trình diễn trong SQLFiddle

+0

Truy vấn ban đầu có c.ParentBId = b.ParentBId thay vì c.parentAID = b.parentBID để điều này có thể không đúng – u07ch

+0

bạn đúng , ngay từ cái nhìn đầu tiên tôi đã không đọc kỹ câu hỏi – mucio

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