2010-10-07 68 views
1

我有一個關於重用表數據的問題,但是在這種情況下視圖將不起作用,因爲我有一個需要傳入的參數。基本上這部分系統需要將travellerid發送到過程,爲特定旅客返回的安排者名單。有大約7個業務規則用於確定哪些編排器可以返回並且它們是互斥的,所以爲了適應這些可選規則,我在派生查詢中使用了一系列UNION。這是行之有效的,而且在一個相當大的數據庫中性能似乎很好,但是我需要在系統的另外四個部分重用這些規則(UNION)。我應該使用T-SQL函數,查看還是存儲過程?

我最初試圖用這些UNION創建一個VIEW,但由於每個UNION的邏輯不同和參數的不同需求,所以我在想也許一個函數可以解決這個問題?如果我創建了一個將@travellerid作爲參數並根據業務規則返回arrangerid列表的函數,這是否是理想的/快速的解決方案?我目前在外部查詢中使用UNION ALL和DISTINCT,因爲這比使用UNION來處理數據的唯一性要快得多。

當前程序下面的業務規則(SQL Server 2008中):

CREATE PROCEDURE [dbo].[getArrangersForTraveller] 
    @travellerid int 
AS 
    DECLARE @costcentreid int 
    DECLARE @departmentid int 

-- Shorthand the traveller costcentre and department for use in queries below 
SET @costcentreid = (SELECT costcentreid FROM traveller WHERE id = @travellerid) 
SET @departmentid = (SELECT departmentid FROM traveller WHERE id = @travellerid) 


SELECT DISTINCT t.id, t.firstname, t.lastname, ti.name AS title, dv.preferred 
FROM traveller t 

INNER JOIN title ti ON t.titleid = ti.id 
    INNER JOIN 

    (

      -- Get Preferred Arrangers linked to Department Groups 
      SELECT dg.arrangerid as id 
      FROM departmentGroup dg 
       INNER JOIN department_departmentGroup ddg 
       ON (dg.id = ddg.departmentGroupId AND ddg.departmentid = @departmentid) 

      UNION ALL 

      -- Get Preferred Arrangers linked to Cost Centre Groups 
      SELECT cg.arrangerid as id 
      FROM costCentreGroup cg 
       INNER JOIN costcentre_costCentreGroup ccg 
       ON (cg.id = ccg.costCentreGroupId AND ccg.costcentreid = @costcentreid) 

      UNION ALL 

      -- If Cost Centre Group has a linked department and this department matches 
      -- the travel arrangers department then return these travel arrangers as well  
      SELECT t3.id 
      FROM costCentreGroup cg1 

       INNER JOIN costcentre_costCentreGroup ccg1 
       ON (cg1.id = ccg1.costCentreGroupId AND ccg1.costcentreid = @costcentreid) 

       INNER JOIN traveller t3 
       ON t3.departmentid = cg1.departmentid  

      WHERE t3.accesslevelid > 1  

      UNION ALL 

      -- Get Direct linked travel arrangers  
      SELECT t1.travelarrangerid as id 
      FROM travelarranger_traveller t1 
      WHERE t1.travellerid = @travellerid 

      UNION ALL 

      -- Get Cost Centre linked arrangers 
      SELECT tc.travelarrangerid as id 
      FROM travelArranger_costcentre tc 
      WHERE tc.costcentreid = @costcentreid 

      UNION ALL 

      -- Get Department linked arrangers 
      SELECT td.travelarrangerid 
      FROM travelArranger_department td 
      WHERE td.departmentid = @departmentid 

      UNION ALL 

      -- Get Company flagged arrangers 
      SELECT t2.id 
      FROM traveller t2 
        INNER JOIN company c ON t2.companyid = c.id 

      WHERE t2.accesslevelid > 1  
      AND ((c.allowTravelArrangerDepartmentAccess = 1 AND t2.departmentid = @departmentid) 
      OR (c.allowTravelArrangerCostCentreAccess = 1 AND t2.costcentreid = @costcentreid)) 

    ) as dv ON dv.id = t.id 

WHERE t.accessLevelid > 1 -- arranger or manager 
AND t.isenabled = 1 
ORDER BY dv.preferred DESC, t.lastname, t.firstname; 

回答

2

我最初試圖建立與這些工會的視圖,但未由於不同的邏輯在每個工會工作不同的參數要求,所以我想也許一個函數可以解決這個問題?如果我創建了一個作爲param @travellerid的函數,並根據業務規則返回了arrangerid的列表,那麼這是一個理想的/快速的解決方案嗎?

你在考慮程序/ OO編程,但SQL是基於SET的。
一個函數可以工作,但是可以確保當你使用函數作爲判定標準/等時,索引不能被使用。一個非物化視圖只是略好一點;在SQL Server中可以使用索引視圖(也稱爲物化視圖),但它們受到了嚴格限制。它違背了模塊化編程的概念,但是SQL運行得越好,試圖模塊化它的能力就越低,只使用你實際需要的東西。

我重新編寫了您的查詢,但注意到dv.preferred列是在外部查詢中引用的,但不在內部列表中。由於dv是各種表&邏輯的集合體,所以返回的id值在內部查詢之外沒有任何實際值,因爲您需要知道值來自哪個表。這就是說,在這裏它是:

SELECT t.id, t.firstname, t.lastname, ti.name AS title /*, dv.preferred */ 
    FROM TRAVELLER t 
    JOIN title ti ON t.titleid = ti.id 
WHERE (EXISTS(SELECT NULL -- Get Preferred Arrangers linked to Department Groups 
       FROM departmentGroup dg 
       JOIN department_departmentGroup ddg ON ddg.departmentGroupId = dg.id 
                AND ddg.departmentid = @departmentid 
       WHERE dg.arrangerid = t.id) 
    OR EXISTS(SELECT NULL -- Get Preferred Arrangers linked to Cost Centre Groups 
       FROM costCentreGroup cg 
       JOIN costcentre_costCentreGroup ccg ON ccg.costCentreGroupId = cg.id 
                AND ccg.costcentreid = @costcentreid 
       WHERE cg.arrangerid = t.id) 
    OR EXISTS(SELECT NULL -- If Cost Centre Group has a linked department and this department matches the travel arrangers department then return these travel arrangers as well  
       FROM costCentreGroup cg1 
       JOIN costcentre_costCentreGroup ccg1 ON ccg1.costCentreGroupId = cg1.id 
                AND ccg1.costcentreid = @costcentreid 
       JOIN traveller t3 ON t3.departmentid = cg1.departmentid  
           AND t3.accesslevelid > 1 
       WHERE t3.id = t.id) 
    OR EXISTS(SELECT NULL -- Get Direct linked travel arrangers  
       FROM travelarranger_traveller t1 
       WHERE t1.travellerid = @travellerid 
       AND t1.travelarrangerid = t.id) 
    OR EXISTS(SELECT NULL -- Get Cost Centre linked arrangers 
       FROM travelArranger_costcentre tc 
       WHERE tc.costcentreid = @costcentreid 
       AND tc.travelarrangerid = t.id) 
    OR EXISTS(SELECT NULL -- Get Department linked arrangers 
       FROM travelArranger_department td 
       WHERE td.departmentid = @departmentid 
       AND td.travelarrangerid = t.id) 
    OR EXISTS(SELECT NULL -- Get Company flagged arrangers 
       FROM traveller t2 
       JOIN company c ON t2.companyid = c.id 
           AND t2.accesslevelid > 1  
       WHERE ( (c.allowTravelArrangerDepartmentAccess = 1 AND t2.departmentid = @departmentid) 
         OR (c.allowTravelArrangerCostCentreAccess = 1 AND t2.costcentreid = @costcentreid)) 
       AND t2.id = t.id)) 
    AND t.accessLevelid > 1 -- arranger or manager 
    AND t.isenabled = 1 
ORDER BY /*dv.preferred DESC,*/ t.lastname, t.firstname; 

使用子查詢(IN,EXISTS)將緩解自帶的使用是否有連接到母體多個子記錄加入重複的問題。

+0

感謝您的快速和詳細的回覆。對不起,我已經從每個UNION中刪除了「首選」標誌,因爲它沒有必要,我在外部選擇中留下了對它的引用。就像你已經擁有的那樣忽略它。隨着查詢的重寫,它仍然有效地使我處於和以前一樣的位置,從而我無法重用這些規則。這些6/7選擇查詢我以前曾經聯合形成了核心業務規則和相同的確切語句,在系統中的其他5個過程中使用,如果添加新規則,這些過程就會變得更加難以維護。 – 2010-10-07 02:52:35

+0

另外我對每個EXISTS子句的SELECT NULL有點困惑?我原以爲這是在每個子查詢中檢查存在的ID。所以你認爲創建一個可重用的函數是爲了加入更慢的性能,因爲給定的編程人員可能會返回多達4000名遊客?謝謝! – 2010-10-07 02:57:13

+0

@Phil Rasmussen:正如我所解釋的,您希望重用我將重申的邏輯:這是一個糟糕的基礎,旨在實現良好的SQL。從維護的角度來看,對您而言很容易,在現實中可能會導致性能下降。如果權衡是值得的,這取決於你。 – 2010-10-07 02:59:28

相關問題