1

我有一个关于重用表数据的问题,但视图在这种情况下不起作用,因为我有一个需要传入的参数。基本上系统的这一部分需要travellerid发送到过程和一个列表安排人员为该特定旅行者返回。大约有 7 个业务规则用于确定可以返回哪些排列器并且它们是互斥的,因此为了适应这些可选规则,我在派生查询中使用了一系列 UNION。这运行良好,并且在相当大的数据库中性能似乎不错,但是我需要在系统的大约 4 个其他部分中重用这些规则 (UNIONS)。

我最初尝试使用这些 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;
4

1 回答 1

2

我最初尝试使用这些 UNION 创建一个 VIEW ,但由于每个 UNION 中的不同逻辑和不同的参数要求,这不起作用,所以我在想也许一个函数可以解决这个问题?如果我创建了一个作为参数@travellerid 的函数,并根据业务规则返回了一个排列的列表,这将是一个理想/快速的解决方案吗?

您正在考虑过程/OO 编程,但 SQL 是基于 SET 的。
一个函数可以工作,但会确保当您将该函数用于决策标准/等时不能使用索引。非物化视图只是稍微好一点;在 SQL Server 中,可以选择使用索引视图(AKA 物化视图),但它们受到了众所周知的限制。它与模块化编程概念背道而驰,但如果您尝试将其模块化并仅使用您实际需要的东西,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)将缓解使用联接带来的重复问题。

于 2010-10-07T01:48:45.213 回答