如何使用Begin和End语句构建动态SQL查询

时间:2011-02-01 15:59:15

标签: sql sql-server tsql

好吧我不是SQL大师或DBA,所以如果有更好的方法可以做到这一点,那么请自由发言。

但是我需要特别做的是增强使用动态SQL的现有存储过程不插入重复值。当对单个表进行specefic时,SQL本身就是小菜一碟。但是现在,我遇到了一个通用存储过程有问题,我通常会为几个表工作并使用TSQL。问题出在BEGIN和END语句中。

    SET @Query =  'IF NOT EXISTS (SELECT ' + @DescriptionFieldName + ' 
       FROM '+ @TableName +'
       WHERE (' + @DescriptionFieldName + ' = ''' + @DescriptionValue + ''') 

    BEGIN
        INSERT INTO '+ @TableName +' (' + @DescriptionFieldName + ', LastUser, LastUpdate) VALUES ('''+ ISNULL(@DescriptionValue, '') +''', '''+ ISNULL(@LastUser, '') +''',Convert(Varchar, GetDate())) '  + 'SELECT CAST(scope_identity() AS int);
    END'

EXEC (@Query)

当我将EXEC更改为PRINT时,所有出现都是正确的语法,但在使用EXEC时出现以下错误:

“关键字'BEGIN'附近的语法不正确。”

有没有人知道如何纠正这个问题,以便查询有效?

谢谢!

2 个答案:

答案 0 :(得分:2)

看起来你在where子句后面有一个缺少的括号。

 SET @Query =  'IF NOT EXISTS (SELECT ' + @DescriptionFieldName + ' 
       FROM '+ @TableName +'
       WHERE (' + @DescriptionFieldName + ' = ' + @DescriptionValue + ') )

    BEGIN
        INSERT INTO '+ @TableName +' (' + @DescriptionFieldName + ', LastUser, LastUpdate) VALUES ('''+ ISNULL(@DescriptionValue, '') +''', '''+ ISNULL(@LastUser, '') +''',Convert(Varchar, GetDate())) '  + 'SELECT CAST(scope_identity() AS int);
    END'

答案 1 :(得分:1)

FWIW,在处理生产中的动态SQL或代码生成时,我喜欢使用模板,这使得它更容易维护(注意你可以嵌入换行符,这也很好 - 不要忘了插入CHAR(13)/ CHAR(10)或在引用前需要空格:

DECLARE @template AS varchar(max) = '
    IF NOT EXISTS (
        SELECT {@DescriptionFieldName} -- Note this is unnecessary
        FROM {@TableName}
        WHERE ({@DescriptionFieldName} = ''{@DescriptionValue}''
    ) 
    BEGIN
        INSERT INTO {@TableName} ({@DescriptionFieldName}, LastUser, LastUpdate)
        VALUES (''{@DescriptionValue}'', ''{@LastUser}'', ''{@LastUpdate}'');
    END
'

DECLARE @Query AS varchar(max) = @template
SET @Query = REPLACE(@Query, '{@DescriptionFieldName}', @DescriptionFieldName)
SET @Query = REPLACE(@Query, '{@TableName}', @TableName)
SET @Query = REPLACE(@Query, '{@DescriptionValue}', ISNULL(@DescriptionValue, ''))
SET @Query = REPLACE(@Query, '{@LastUser}', ISNULL(@LastUser, ''))
SET @Query = REPLACE(@Query, '{@LastUpdate}', @LastUpdate)

PRINT @Query
EXEC (@Query)

你仍然有两倍的引号,但你不必添加字符串,当你忘记更换参数时很明显,并且当事情必须改变时你不会在代码中重复插入。

另请注意,@DescriptionValue中的NULL可能存在问题(您的原始文件在EXISTS的WHERE部分中存在同样的问题)

请注意,您也可以嵌套替换,并使用适当的格式,它甚至可以读取:

DECLARE @Query AS varchar(max) = @template
SET @Query = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@Query
                 ,'{@DescriptionFieldName}', @DescriptionFieldName)
                 ,'{@TableName}', @TableName)
                 ,'{@DescriptionValue}', ISNULL(@DescriptionValue, ''))
                 ,'{@LastUser}', ISNULL(@LastUser, ''))
                 ,'{@LastUpdate}', @LastUpdate)