【问题标题】:combine two SPs in SQL Server在 SQL Server 中组合两个 SP
【发布时间】:2013-03-19 07:45:17
【问题描述】:

我有两个冗余代码的存储过程。 SP 将根据从中选择的表而有所不同。我想结合这两个SP。请帮忙。

主要的SP是:

CREATE PROCEDURE [dbo].[spGetEmployeesBySearchString]            
-------------
-------------
@OtherListType_ID INT
@manager_employee_number VARCHAR(255)
-------------
-------------
DECLARE @IsGetFullTeamUnderManager bit=0
IF (@OtherListType_ID=3 AND @manager_employee_number IS NOT NULL)
    SET @IsGetFullTeamUnderManager = 1

IF (@IsGetFullTeamUnderManager=1)
BEGIN
    EXEC spFullTeamUnderManager <<Parameters>>
    RETURN
END

SELECT e.a,e.b,e.c,e.d,......
FROM Employee emp
INNER JOIN .....
WHERE ..........

第二个存储过程是:

CREATE PROCEDURE [dbo].[spFullTeamUnderManager]            
-------------
-------------
-------------
SELECT e.a,e.b,e.c,e.d,......
FROM dbo.fnFullTeamUnderManager(@manager_employee_number) emp 
INNER JOIN .....
WHERE ..........

在主 SP 中,基于@OtherListType_ID 的值,我正在调用第二个 SP。但是两个存储过程中的 select 语句、连接条件和 where 条件保持不变。我需要删除多余的代码。请帮忙。

【问题讨论】:

    标签: sql sql-server-2008 stored-procedures redundancy


    【解决方案1】:

    通常,您不能在FROM 子句中对行集源进行参数化。您可以执行以下操作,并希望优化器足够聪明以正确执行此操作:

    SELECT e.a,e.b,e.c,e.d,......
    FROM (
     SELECT * FROM dbo.fnFullTeamUnderManager(@manager_employee_number) WHERE @IsGetFullTeamUnderManager=1
     UNION ALL
     SELECT * FROM Employee WHERE @IsGetFullTeamUnderManager=0
    ) emp 
    INNER JOIN .....
    WHERE ..........
    

    如果函数和 Employee 不共享完全相同的列,则您必须明确命名公共列,而不是使用 SELECT * - 有些人可能坚持认为您应该这样做,但今天我'以“完成它”的心情。

    【讨论】:

    • 我觉得应该是UNION;这将有助于删除重复项。
    • @Damien :例如,如果函数只返回 12 行,而员工表有 5000 行,并且假设我只需要函数的输出(考虑第二个 SP),那么在这种情况下也是将返回两个条件中的所有行,它会失败吗?
    • @ColourBlend - WHERE 子句是互斥的。
    • @prabuR - WHERE 子句是互斥的 - 它要么从函数中选择,要么从 Employee 中选择,但从不同时选择两者。正如我所说,希望优化器可以看到这一点并且实际上不会执行无意义的工作,但WHERE 子句应该防止它从两个分支返回行
    • @Damien_The_Unbeliever 好的,现在看到WHERE @IsGetFullTeamUnderManager=0。更好的解决方案:)
    【解决方案2】:
    CREATE PROCEDURE [dbo].[spGetEmployeesBySearchString]            
    -------------
    -------------
    @OtherListType_ID INT,
    @manager_employee_number VARCHAR(255)
    -------------
    -------------
    DECLARE @IsGetFullTeamUnderManager bit=0
    IF (@OtherListType_ID=@FullTeam AND @manager_employee_number IS NOT NULL)
        SET @IsGetFullTeamUnderManager = 1
    
    IF (@IsGetFullTeamUnderManager=1)
    BEGIN    
        SELECT e.a,e.b,e.c,e.d,......
        FROM dbo.fnFullTeamUnderManager(@manager_employee_number) emp 
        INNER JOIN .....    
        WHERE ..........    
    END
    
    SELECT e.a,e.b,e.c,e.d,......
    FROM Employee emp
    INNER JOIN .....
    WHERE ..........
    

    【讨论】:

    • 这里我还需要重复整个 select 语句、join 条件和 where 条件。主要目的是消除冗余,因为 SP 中有更多的条件。有没有其他办法?
    • 你能举出所有条件的函数和选择语句的例子吗?
    【解决方案3】:
    CREATE PROCEDURE [dbo].[spGetEmployeesBySearchString]            
    -------------
    -------------
    @OtherListType_ID INT
    @manager_employee_number VARCHAR(255)
    -------------
    -------------
    
    -- Me
    DECLARE @SQL varchar(3000);
    DECLARE @TableName varchar(30);
    SET @TableName = 'Employee ';
    
    
    
    DECLARE @IsGetFullTeamUnderManager bit=0
    IF (@OtherListType_ID=3 AND @manager_employee_number IS NOT NULL)
        SET @IsGetFullTeamUnderManager = 1
    
    IF (@IsGetFullTeamUnderManager=1)
    BEGIN
        SET @TableName = 'dbo.fnFullTeamUnderManager(' + @manager_employee_number +') ';
    END
    
    SET @SQL = 'SELECT e.a,e.b,e.c,e.d
                FROM ' + @TableName + ' emp
                INNER JOIN .....
                WHERE a = ' + convert(varchar(4), @aNumber);
    
    EXEC(@SQL);
    

    您还应该知道执行动态 sql 语句的更好方法。

    使用EXEC SP_EXECUTESQL(@SQL) 而不是EXEC(@SQL) 更有可能促进查询计划重用并提高安全性。此外,使用这种方法可以确保传递给查询的数据值是正确的数据类型。

    更多阅读 Execute Dynamic SQL commands in SQL Server

    【讨论】:

      猜你喜欢
      • 2017-11-17
      • 1970-01-01
      • 1970-01-01
      • 2012-03-07
      • 1970-01-01
      • 2020-10-11
      • 2017-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多