我有一个关于重用表数据的问题但是视图在这种情况下不起作用,因为我有一个需要传入的参数。基本上这部分系统需要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;
答案 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)将减轻使用连接时出现的重复问题(如果有多个子记录附加到父级)。