复杂的存储过程

Car*_*rel 1 sql stored-procedures join subquery sql-server-2012

我是关于sql的新手,我正在尝试创建一个相当复杂的存储过程,该过程将由使用Visual Studio商业智能中的sql报告服务创建的报告使用.

我有一个主要的"项目"表,通过使用链接表(我的存储过程中感兴趣的是"状态","设施"和"分支")链接各种其他表.该应用程序的作用是研究人员提交项目,并通过以下批准过程:

专业健康经理>分科主任>健康管理团队

为了促进此批准过程,另一个团队成员开发了一个使用"WorkflowHistory"表的自定义工作流解决方案.放入此表(以及其他)的是ProjectId,WorkflowStep和执行工作流程步骤的日期以及执行该步骤的人员发布的评论.我在报告中想要的是以下内容:

我在报告中想要的信息如下:

火星报告字段

'ProjectId'和'Title'来自'Project'表.表格中的"设施","分支"和"状态"com链接到"项目"."收到的"需要是为项目执行初始工作流程步骤的日期."结束"需要是为项目执行最终工作流程步骤的日期."评论"需要是留给最终工作流程步骤的评论.

因此,报告中每行的数据来自以下地方:

  • "项目"中的一行
  • 来自'Branch'的一行
  • "状态"中的一行
  • 来自'Facility'的多行(在我的运行尝试下面我只返回子查询中的第一个工具,但我想要分配给项目的所有工具,逗号空间分隔)
  • "WorkflowHistory"中的两行不同

用户传递以下参数以过滤报告:

  • 从日期开始 - 获取特定日期之后收到的所有报告(这将是'WorkflowHistory'中第一个工作流程步骤的'ActionedOn')
  • 到目前为止 - 在特定日期之前收到所有报告(这将是'WorkflowHistory'中最后工作流程步骤的'ActionedOn')
  • 状态 - 筛选具有特定状态的项目
  • 分支 - 过滤分配给特定分支的项目

火星报告参数

我试图通过以下存储过程完成所有这些.这是我的奔跑尝试,我一直在努力.我仍然遇到的问题包括:

  • 日期范围过滤不起作用
  • 我只能返回子查询中的第一个工具(以下是注释掉整个WHERE部分时仍然存在的问题)
  • 项目的最终工作流程步骤可能是2到5之间的任何步骤,具体取决于它是否被批准以及何时被拒绝.我需要弄清楚如何获得"结束"日期以及此步骤中的评论.
  • 我在参数中传递'Status'.我需要弄清楚如何通过一个状态或所有状态(实际上并非所有状态,但最终的3个被'已批准','拒绝'和'结束')进行过滤.分支相同.

编辑:现在是什么,5小时后,我已经更新了下面的存储过程.我通过使用临时表变量对大部分问题进行了排序

CREATE PROCEDURE [dbo].[stp_CityHealthResearchRequestsReport]
@FromDate DATETIME,
@ToDate DATETIME,
@StatusId int,
@BranchId int,
@Count INT OUTPUT
AS
BEGIN
DECLARE @TempTable TABLE
(
    ProjectId INT,
    Recieved DATETIME,
    Concluded DATETIME,
    Comment VARCHAR(8000)
)

IF @StatusId <> 0 AND @BranchId <> 0
BEGIN

    INSERT INTO @TempTable (ProjectId, Recieved, Concluded, Comment)
    SELECT DISTINCT
        p.ProjectId,
        (SELECT TOP 1 wf.ActionedOn
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 1
         ORDER BY wf.WorkflowHistoryId DESC) AS Recieved,
        (SELECT TOP 1 wf.ActionedOn
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 4
         OR wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 5
         ORDER BY wf.WorkflowHistoryId DESC) AS Concluded,
        (SELECT TOP 1 wf.Comment
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 4
         OR wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 5
         ORDER BY wf.WorkflowHistoryId DESC) AS Comment
    FROM
        Project p
        JOIN WorkflowHistory w ON p.ProjectId = w.ProjectId
        JOIN ProjectBranch pb ON pb.ProjectId = p.ProjectId
    WHERE
        p.ProjectId = w.ProjectId
        AND p.StatusId = @StatusId
        AND pb.BranchId = @BranchId
        AND w.WorkflowStep = 1
        AND (w.ActionedOn BETWEEN @FromDate AND @ToDate)

    SELECT DISTINCT
        p.ProjectId,
        p.Title,
        STUFF (
               (SELECT ', ' + f.Name
                FROM dbo.Facility f
                LEFT JOIN dbo.ProjectFacility pf ON f.FacilityId = pf.FacilityId
                WHERE pf.ProjectId = p.ProjectId
                FOR XML PATH (''))
                , 1, 1, '') AS Facilities,
        tt.Recieved,
        tt.Concluded,
        b.BranchName,
        st.Description AS StatusText,
        tt.Comment,
        tt.Concluded - tt.Recieved AS Turnaround
    FROM
        dbo.Project p
        INNER JOIN @TempTable tt ON p.ProjectId = tt.ProjectId
        LEFT JOIN dbo.ProjectBranch pb ON p.ProjectId = pb.ProjectId
        LEFT JOIN dbo.Branch b ON pb.BranchId = b.BranchId
        LEFT JOIN dbo.Status st ON p.StatusId = st.StatusId
    WHERE
        p.StatusId = @StatusId
        AND b.BranchId = @BranchId
    SET @Count = @@ROWCOUNT
END

IF @StatusId <> 0 AND @BranchId = 0
BEGIN

    INSERT INTO @TempTable (ProjectId, Recieved, Concluded, Comment)
    SELECT DISTINCT
        p.ProjectId,
        (SELECT TOP 1 wf.ActionedOn
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 1
         ORDER BY wf.WorkflowHistoryId DESC) AS Recieved,
        (SELECT TOP 1 wf.ActionedOn
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 4
         OR wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 5
         ORDER BY wf.WorkflowHistoryId DESC) AS Concluded,
        (SELECT TOP 1 wf.Comment
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 4
         OR wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 5
         ORDER BY wf.WorkflowHistoryId DESC) AS Comment
    FROM
        Project p
        JOIN WorkflowHistory w ON p.ProjectId = w.ProjectId
        JOIN ProjectBranch pb ON pb.ProjectId = p.ProjectId
    WHERE
        p.ProjectId = w.ProjectId
        AND p.StatusId = @StatusId
        AND w.WorkflowStep = 1
        AND (w.ActionedOn BETWEEN @FromDate AND @ToDate)

    SELECT DISTINCT
        p.ProjectId,
        p.Title,
        STUFF (
               (SELECT ', ' + f.Name
                FROM dbo.Facility f
                LEFT JOIN dbo.ProjectFacility pf ON f.FacilityId = pf.FacilityId
                WHERE pf.ProjectId = p.ProjectId
                FOR XML PATH (''))
                , 1, 1, '') AS Facilities,
        tt.Recieved,
        tt.Concluded,
        b.BranchName,
        st.Description AS StatusText,
        tt.Comment,
        tt.Concluded - tt.Recieved AS Turnaround
    FROM
        dbo.Project p
        INNER JOIN @TempTable tt ON p.ProjectId = tt.ProjectId
        LEFT JOIN dbo.ProjectBranch pb ON p.ProjectId = pb.ProjectId
        LEFT JOIN dbo.Branch b ON pb.BranchId = b.BranchId
        LEFT JOIN dbo.Status st ON p.StatusId = st.StatusId
    WHERE
        p.StatusId = @StatusId
    SET @Count = @@ROWCOUNT
END

IF @StatusId = 0 AND @BranchId <> 0
BEGIN

    INSERT INTO @TempTable (ProjectId, Recieved, Concluded, Comment)
    SELECT DISTINCT
        p.ProjectId,
        (SELECT TOP 1 wf.ActionedOn
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 1
         ORDER BY wf.WorkflowHistoryId DESC) AS Recieved,
        (SELECT TOP 1 wf.ActionedOn
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 4
         OR wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 5
         ORDER BY wf.WorkflowHistoryId DESC) AS Concluded,
        (SELECT TOP 1 wf.Comment
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 4
         OR wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 5
         ORDER BY wf.WorkflowHistoryId DESC) AS Comment
    FROM
        Project p
        JOIN WorkflowHistory w ON p.ProjectId = w.ProjectId
        JOIN ProjectBranch pb ON pb.ProjectId = p.ProjectId
    WHERE
        p.ProjectId = w.ProjectId
        AND p.StatusId = 5
        AND pb.BranchId = @BranchId
        AND w.WorkflowStep = 1
        AND (w.ActionedOn BETWEEN @FromDate AND @ToDate)
        OR p.ProjectId = w.ProjectId
        AND p.StatusId = 6
        AND pb.BranchId = @BranchId
        AND w.WorkflowStep = 1
        AND (w.ActionedOn BETWEEN @FromDate AND @ToDate)
        OR p.ProjectId = w.ProjectId
        AND p.StatusId = 7
        AND pb.BranchId = @BranchId
        AND w.WorkflowStep = 1
        AND (w.ActionedOn BETWEEN @FromDate AND @ToDate)

    SELECT DISTINCT
        p.ProjectId,
        p.Title,
        STUFF (
               (SELECT ', ' + f.Name
                FROM dbo.Facility f
                LEFT JOIN dbo.ProjectFacility pf ON f.FacilityId = pf.FacilityId
                WHERE pf.ProjectId = p.ProjectId
                FOR XML PATH (''))
                , 1, 1, '') AS Facilities,
        tt.Recieved,
        tt.Concluded,
        b.BranchName,
        st.Description AS StatusText,
        tt.Comment,
        tt.Concluded - tt.Recieved AS Turnaround
    FROM
        dbo.Project p
        INNER JOIN @TempTable tt ON p.ProjectId = tt.ProjectId
        LEFT JOIN dbo.ProjectBranch pb ON p.ProjectId = pb.ProjectId
        LEFT JOIN dbo.Branch b ON pb.BranchId = b.BranchId
        LEFT JOIN dbo.Status st ON p.StatusId = st.StatusId
    WHERE
        p.StatusId = 5
        AND pb.BranchId = @BranchId
        OR p.StatusId = 6
        AND pb.BranchId = @BranchId
        OR p.StatusId = 7
        AND pb.BranchId = @BranchId
    SET @Count = @@ROWCOUNT
END

IF @StatusId = 0 AND @BranchId = 0
BEGIN

    INSERT INTO @TempTable (ProjectId, Recieved, Concluded, Comment)
    SELECT DISTINCT
        p.ProjectId,
        (SELECT TOP 1 wf.ActionedOn
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 1
         ORDER BY wf.WorkflowHistoryId DESC) AS Recieved,
        (SELECT TOP 1 wf.ActionedOn
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 4
         OR wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 5
         ORDER BY wf.WorkflowHistoryId DESC) AS Concluded,
        (SELECT TOP 1 wf.Comment
         FROM WorkflowHistory wf
         WHERE wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 4
         OR wf.ProjectId = p.ProjectId
         AND wf.WorkflowStep = 5
         ORDER BY wf.WorkflowHistoryId DESC) AS Comment
    FROM
        Project p
        JOIN WorkflowHistory w ON p.ProjectId = w.ProjectId
        JOIN ProjectBranch pb ON pb.ProjectId = p.ProjectId
    WHERE
        p.ProjectId = w.ProjectId
        AND p.StatusId = 5
        AND w.WorkflowStep = 1
        AND (w.ActionedOn BETWEEN @FromDate AND @ToDate)
        OR p.ProjectId = w.ProjectId
        AND p.StatusId = 6
        AND w.WorkflowStep = 1
        AND (w.ActionedOn BETWEEN @FromDate AND @ToDate)
        OR p.ProjectId = w.ProjectId
        AND p.StatusId = 7
        AND w.WorkflowStep = 1
        AND (w.ActionedOn BETWEEN @FromDate AND @ToDate)

    SELECT DISTINCT
        p.ProjectId,
        p.Title,
        STUFF (
               (SELECT ', ' + f.Name
                FROM dbo.Facility f
                LEFT JOIN dbo.ProjectFacility pf ON f.FacilityId = pf.FacilityId
                WHERE pf.ProjectId = p.ProjectId
                FOR XML PATH (''))
                , 1, 1, '') AS Facilities,
        tt.Recieved,
        tt.Concluded,
        b.BranchName,
        st.Description AS StatusText,
        tt.Comment,
        tt.Concluded - tt.Recieved AS Turnaround
    FROM
        dbo.Project p
        INNER JOIN @TempTable tt ON p.ProjectId = tt.ProjectId
        LEFT JOIN dbo.ProjectBranch pb ON p.ProjectId = pb.ProjectId
        LEFT JOIN dbo.Branch b ON pb.BranchId = b.BranchId
        LEFT JOIN dbo.Status st ON p.StatusId = st.StatusId
    WHERE
        p.StatusId = 5
        OR p.StatusId = 6
        OR p.StatusId = 7
    SET @Count = @@ROWCOUNT
END
END
Run Code Online (Sandbox Code Playgroud)

Tom*_*omT 6

您的代码几乎没有问题:

  • 你一遍又一遍地重复相同的代码.而是通过@StatusId和@BranchId进行分支,您可以在WHERE子句中处理它.
  • 您使用@StatusId = 0和@BranchId = 0来表示缺失值,这应该用NULL表示.
  • 在使用标量相关子查询的地方,我会使用连接.

足够说话,我相信这个查询可以做你想要的:

-- find out the final step for each project
WITH FinalStep AS
(
    SELECT ProjectId, MAX(WorkflowStep) as MaxWorkflowStep
    FROM WorkflowHistory
    WHERE WorkflowStep > 1
    GROUP BY ProjectId
)
SELECT
    p.ProjectId,
    p.Title,
    -- this is ugly consider creating a scalar function to encapsulate it
    STUFF (
           (SELECT ', ' + f.Name
            FROM dbo.Facility f
            LEFT JOIN dbo.ProjectFacility pf ON f.FacilityId = pf.FacilityId
            WHERE pf.ProjectId = p.ProjectId
            FOR XML PATH (''))
            , 1, 1, '') AS Facilities,
    wf1.ActionedOn AS Recieved,
    wf2.ActionedOn AS Concluded,
    b.BranchName,
    st.Description AS StatusText,
    wf2.Comment,
    wf2.ActionedOn - w1.ActionedOn AS Turnaround
FROM
    Project p
    INNER JOIN WorkflowHistory wf1 
        ON p.ProjectId = wf1.ProjectId 
        AND wf1.WorkflowStep = 1
    LEFT JOIN FinalStep fs 
        ON fs.ProjectId = p.ProjectId
    LEFT JOIN WorkflowHistory wf2 
        ON p.ProjectId = wf2.ProjectId 
        AND wf2.WorkflowStep = fs.MaxWorkflowStep
    INNER JOIN ProjectBranch pb 
        ON pb.ProjectId = p.ProjectId
    LEFT JOIN dbo.Branch b 
        ON pb.BranchId = b.BranchId
    LEFT JOIN dbo.Status st 
        ON p.StatusId = st.StatusId
WHERE
    p.ProjectId = w.ProjectId
    -- IF @StatusId = 0 THEN p.StatusId = 5 or 6 or 7 ELSE p.StatusId = @StatusId
    AND ((@StatusId = 0 AND p.StatusId IN (5,6,7)) OR p.StatusId = @StatusId)
    -- IF @BranchId = 0 THEN no filter ELSE pb.BranchId = @BranchId
    AND (@BranchId = 0 OR pb.BranchId = @BranchId)
    AND (wf1.ActionedOn BETWEEN @FromDate AND @ToDate)
Run Code Online (Sandbox Code Playgroud)

我不知道为什么日期过滤器不起作用,对我来说没问题.我没有检查设施连接,但你应该能够很容易谷歌这个东西.我建议你将代码提取到一个函数中.然后,您可以单独测试它,查询看起来会更好.