存储过程,构建SQL语句

时间:2015-06-18 15:50:17

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

参考:我看了SQL Server stored procedure parameters开始。

问题:

我想根据通过存储过程传入​​的数据制作不同的SQL语句。这个例子涉及一个版本,但会有几个版本,我想保持我的代码一致。

错误:

  

消息102,级别15,状态1,过程spSearchGrid,第60行   '@SQL'附近的语法不正确。   Msg 103,Level 15,State 4,Procedure spSearchGrid,Line 60   以'SELECT p.ID AS ID,p.UPRN AS UPRN,COALESCE(a.OverallRiskCategory,'Unknown')开头的标识符AS OverallRiskCategory,COALESCE(a.TypeOfUtility,'U'太长。最大长度为128。   消息102,级别15,状态1,过程spSearchGrid,第65行   '@SQL'附近的语法不正确。   Msg 103,Level 15,State 4,Procedure spSearchGrid,66行   以@sDateFrom和@sDateTo之间的'a.SurveyDate开头的标识符AND(p.UPRN LIKE'%'+ @sUPRN +'%'或                       p.PostCode LIKE'%'+ @sPostcode +'太长了。最大长度为128。   消息102,级别15,状态1,过程spSearchGrid,第76行   'END'附近的语法不正确。

尝试:

我尝试在外围使用单一和双重语音标记,但这并没有帮助解决问题。

代码:

USE [Database]
GO
/****** Object:  StoredProcedure [dbo].[spSearchGrid]    Script Date: 18/06/2015 15:14:06 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
ALTER PROCEDURE [dbo].[spSearchGrid]

@sUPRN varchar(150),
@sPostcode varchar(20),
@sDateFrom datetime,
@sDateTo datetime,
--@sUCARN varchar(20),
@sPropertyName varchar(20),
@sStreet varchar(150),
@sSurveyCompany  varchar(150),
@sRiskRating varchar(150),
@sRegion varchar(150)
-- Add the parameters for the stored procedure here
 --@test1 VARCHAR(30) OUTPUT

AS

BEGIN
--and 
DECLARE @SQL VARCHAR(MAX)

 If @sUPRN = 'Test' 
 BEGIN
    @SQL = SELECT p.ID AS ID, p.UPRN AS UPRN, COALESCE(a.OverallRiskCategory,'Unknown') AS OverallRiskCategory, COALESCE(a.TypeOfUtility,'Unknown') AS TypeOfUtility, COALESCE(a.SurveyDate,'') AS SurveyDate, COALESCE(a.ItemRef, '') AS ItemRef, COALESCE(a.NextAsbestosSurveyDue,'') AS NextAsbestosSurveyDue , COALESCE(a.Recommendations,'NO DATA') AS Recommendations, COALESCE(a.StatusOfIssue,'0') As StatusOfIssue 
    FROM TblProperty AS p LEFT  JOIN TblAsbestos AS a on  a.UPRN = p.UPRN WHERE

    IF LTRIM(RTRIM(@sRiskRating)) = '1234xyz'

    @SQL += a.OverallRiskCategory = LTRIM(RTRIM(@sRiskRating)) AND 
    @SQL += a.SurveyDate between @sDateFrom and @sDateTo AND (p.UPRN LIKE  '%' + @sUPRN + '%'   or
                    p.PostCode LIKE '%' + @sPostcode + '%'  or
                    p.ShopName LIKE '%' + @sPropertyName + '%'  or
                    p.Street LIKE '%' + @sStreet + '%'  or
                    p.Reg = @sRegion  or
                    a.SurveyCompany LIKE '%' + @sSurveyCompany + '%' )
 END

  --PRINT(@SQL)
  EXEC(@SQL)    
END

2 个答案:

答案 0 :(得分:1)

您需要通过在其前添加其他引号来确保您的报价已转义。

此外,初始化@SQL变量时以及当您尝试在IF部分中向其添加更多代码时会出现一些问题。

试试这个:

USE [Database]
GO
/****** Object:  StoredProcedure [dbo].[spSearchGrid]    Script Date: 18/06/2015 15:14:06 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
ALTER PROCEDURE [dbo].[spSearchGrid]

@sUPRN varchar(150),
@sPostcode varchar(20),
@sDateFrom datetime,
@sDateTo datetime,
--@sUCARN varchar(20),
@sPropertyName varchar(20),
@sStreet varchar(150),
@sSurveyCompany  varchar(150),
@sRiskRating varchar(150) = NULL,
@sRegion varchar(150)
-- Add the parameters for the stored procedure here
 --@test1 VARCHAR(30) OUTPUT

AS

BEGIN
--and 
DECLARE @SQL VARCHAR(MAX)

 If @sUPRN = 'Test' 
 BEGIN
    SET @SQL = 'SELECT p.ID AS ID, p.UPRN AS UPRN, COALESCE(a.OverallRiskCategory,''Unknown'') AS OverallRiskCategory, COALESCE(a.TypeOfUtility,''Unknown'') AS TypeOfUtility, COALESCE(a.SurveyDate,'''') AS SurveyDate, COALESCE(a.ItemRef, '''') AS ItemRef, COALESCE(a.NextAsbestosSurveyDue,'''') AS NextAsbestosSurveyDue , COALESCE(a.Recommendations,''NO DATA'') AS Recommendations, COALESCE(a.StatusOfIssue,''0'') As StatusOfIssue 
    FROM TblProperty AS p LEFT  JOIN TblAsbestos AS a on  a.UPRN = p.UPRN WHERE'

    IF LTRIM(RTRIM(@sRiskRating)) = '1234xyz'
    BEGIN
    SET @SQL = @SQL + 'a.OverallRiskCategory = LTRIM(RTRIM(@sRiskRating)) AND '
    SET @SQL = @SQL + 'a.SurveyDate between @sDateFrom and @sDateTo AND (p.UPRN LIKE  ''%'' + @sUPRN + ''%''   or
                    p.PostCode LIKE ''%'' + @sPostcode + ''%''  or
                    p.ShopName LIKE ''%'' + @sPropertyName + ''%''  or
                    p.Street LIKE ''%'' + @sStreet + ''%''  or
                    p.Reg = @sRegion  or
                    a.SurveyCompany LIKE ''%'' + @sSurveyCompany + ''%'' )'
    END
 END

  --PRINT(@SQL)
  EXEC(@SQL)    
END

答案 1 :(得分:0)

我在这里看不到动态sql的需求。您拥有的是基于某些参数的具有多个执行路径的过程。这很常见,你真的不需要求助于动态。原始逻辑似乎存在一些逻辑问题。如果@sUPRN的值不是'测试'这个程序没有做任何事情。我猜这是不正确的,但这取决于OP来确定。

将所有这些逻辑保留在一个程序中是可行的,但它会有轻微的性能损失。因为您需要执行两个不同的查询,所以您可能需要针对不同查询执行计划。实现此目的的一种方法(我将很快发布的方式)是为您的查询添加重新编译选项。这会强制优化器在运行后抛弃执行计划,因此它总是会得到一个新的编译。这意味着每次运行此过程时,都必须首先重新编译它。一个更好的方法,我将在我的系统上采用的方法是为每个路径创建一个子过程。这允许为每个分支缓存计划。

以下是如何在没有任何动态sql的情况下执行此操作并保持性能良好。

ALTER PROCEDURE [dbo].[spSearchGrid]
(
    @sUPRN varchar(150),
    @sPostcode varchar(20),
    @sDateFrom datetime,
    @sDateTo datetime,
    @sPropertyName varchar(20),
    @sStreet varchar(150),
    @sSurveyCompany  varchar(150),
    @sRiskRating varchar(150) = NULL,
    @sRegion varchar(150)
) AS
BEGIN
    SET NOCOUNT ON

    If @sUPRN = 'Test' 
        IF LTRIM(RTRIM(@sRiskRating)) = '1234xyz'
            SELECT p.ID AS ID
                , p.UPRN AS UPRN
                , COALESCE(a.OverallRiskCategory, 'Unknown') AS OverallRiskCategory
                , COALESCE(a.TypeOfUtility, 'Unknown') AS TypeOfUtility
                , COALESCE(a.SurveyDate, '') AS SurveyDate --Is this really a date? If so, this will become 1/1/1900
                , COALESCE(a.ItemRef, '') AS ItemRef
                , COALESCE(a.NextAsbestosSurveyDue, '') AS NextAsbestosSurveyDue
                , COALESCE(a.Recommendations, 'NO DATA') AS Recommendations
                , COALESCE(a.StatusOfIssue, '0') As StatusOfIssue 
            FROM TblProperty AS p 
            LEFT JOIN TblAsbestos AS a on a.UPRN = p.UPRN 
            WHERE a.OverallRiskCategory = LTRIM(RTRIM(@sRiskRating)) 
                AND a.SurveyDate between @sDateFrom and @sDateTo 
                AND 
                (
                    p.UPRN LIKE '%' + @sUPRN + '%'   
                    OR p.PostCode LIKE '%' + @sPostcode + '%'
                    OR p.ShopName LIKE '%' + @sPropertyName + '%'
                    OR p.Street LIKE '%' + @sStreet + '%'
                    OR p.Reg = @sRegion
                    OR a.SurveyCompany LIKE '%' + @sSurveyCompany + '%'
                )
            OPTION (RECOMPILE)
        ELSE
            SELECT p.ID AS ID
                , p.UPRN AS UPRN
                , COALESCE(a.OverallRiskCategory, 'Unknown') AS OverallRiskCategory
                , COALESCE(a.TypeOfUtility, 'Unknown') AS TypeOfUtility
                , COALESCE(a.SurveyDate, '') AS SurveyDate --Is this really a date? If so, this will become 1/1/1900
                , COALESCE(a.ItemRef, '') AS ItemRef
                , COALESCE(a.NextAsbestosSurveyDue, '') AS NextAsbestosSurveyDue
                , COALESCE(a.Recommendations, 'NO DATA') AS Recommendations
                , COALESCE(a.StatusOfIssue, '0') As StatusOfIssue 
            FROM TblProperty AS p 
            LEFT JOIN TblAsbestos AS a on a.UPRN = p.UPRN 
            OPTION (RECOMPILE)
    --there is nothing to do if @sUPRN is not 'Test'???
END

Gail Shaw在她的博客上发表了一篇关于这个主题的优秀文章。她也更喜欢把它分成3个程序,但我没有在这里做。阅读本文并自行决定哪些适合您。 http://sqlinthewild.co.za/index.php/2009/09/15/multiple-execution-paths/