我应该使用T-SQL函数,查看还是存储过程?

时间:2010-10-07 00:54:55

标签: sql stored-procedures function select union-all

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

我最初尝试使用这些UNIONS创建一个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;

1 个答案:

答案 0 :(得分:2)

  

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

您正在考虑过程/ 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)将减轻使用连接时出现的重复问题(如果有多个子记录附加到父级)。