存储过程INSERT执行报错:‘=’附近语法不正确
咱们来一步步拆解这个问题,理清楚哪里出了问题:
先看你的存储过程和调用语句
你创建的SP_v2存储过程代码如下:
ALTER PROCEDURE [dbo].[SP_v2] @CashCountBatchNo INT, @CashierID VARCHAR(10), @Remarks VARCHAR(50), @CashCount NVARCHAR(1000), @ADJ NVARCHAR(1000) = '', @CutOff VARCHAR(8) = '' AS SET NOCOUNT ON DECLARE @tbl TABLE(DENOMINATION MONEY, [COUNT] INT) DECLARE @tblADJ TABLE(Description VARCHAR(300), Amount MONEY) DECLARE @Totals TABLE(CC MONEY, CH MONEY, CASHTOCOLLECT MONEY) SET @CashCount = REPLACE(@CashCount, '_S_', ' Select ') SET @CashCount = REPLACE(@CashCount, '_;', ' union all ') SET @CashCount = SUBSTRING(@CashCount, 0, LEN(@CashCount) - 8) INSERT INTO @tbl(DENOMINATION, [COUNT]) EXEC sp_executesql @CashCount SELECT * FROM @tbl RETURN
调用时使用的语句:
UERMHIMS..Usp_Cashier_SaveCashCount_v2 '', '', '', 'DENOMINATION=1000, COUNT=1 union select DENOMINATION=500, COUNT=1', '', ''
抛出的错误信息:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '='.
错误根源分析
问题出在动态SQL的构造逻辑上,咱们一步步追踪@CashCount的变化:
- 你传入的
@CashCount字符串里既没有_S_也没有_;,所以存储过程里的前两次REPLACE操作完全没起作用,字符串保持原样。 - 接下来的
SUBSTRING会截掉字符串末尾8个字符,原字符串末尾是, COUNT=1,截完后变成'DENOMINATION=1000, COUNT=1 union select DENOMINATION=500'——但这不是核心问题,核心是这个字符串本身就不是合法的SQL语句!
SQL中构造行数据不能直接写DENOMINATION=1000, COUNT=1,这种写法会让SQL解析器误以为DENOMINATION是变量或列名,遇到=时就会触发语法错误。正确的写法应该是SELECT 1000 AS DENOMINATION, 1 AS COUNT或者使用VALUES子句。
另外,从存储过程的REPLACE逻辑来看,它似乎期望你传入带特殊标记的字符串(比如'_S_ DENOMINATION=1000, COUNT=1 _; _S_ DENOMINATION=500, COUNT=1'),替换后会生成' Select DENOMINATION=1000, COUNT=1 union all Select DENOMINATION=500, COUNT=1'——但就算是这样,DENOMINATION=1000的写法依然不合法,还是会报错。
解决办法
给你两个可行的调整方向:
方向1:直接修正传入的参数格式
把@CashCount改成合法的SELECT语句片段,比如:
UERMHIMS..Usp_Cashier_SaveCashCount_v2 '', '', '', 'SELECT 1000 AS DENOMINATION, 1 AS COUNT union select 500 AS DENOMINATION, 1 AS COUNT', '', ''
同时记得删除存储过程里的SUBSTRING(@CashCount, 0, LEN(@CashCount) - 8)语句——这个逻辑是针对带_;标记的字符串设计的,现在参数格式变了,就不需要了。
方向2:调整存储过程的动态SQL生成逻辑
如果你想保留DENOMINATION=xxx, COUNT=xxx的简洁传入格式,可以修改存储过程里的替换逻辑,把这种格式转换成合法的SQL:
-- 将传入的片段转换为合法的SELECT语句 SET @CashCount = REPLACE(@CashCount, 'DENOMINATION=', 'SELECT ') SET @CashCount = REPLACE(@CashCount, ', COUNT=', ' AS DENOMINATION, ') SET @CashCount = REPLACE(@CashCount, ' union select ', ' AS COUNT union select ') SET @CashCount = @CashCount + ' AS COUNT'
这个逻辑可以根据你实际的传入格式微调,确保最终生成的SQL语法合法。
最后提醒一句:当前存储过程存在SQL注入风险,因为它直接执行用户传入的字符串。如果是生产环境使用,建议要么对传入内容做严格校验,要么改用参数化动态SQL,避免安全隐患。
内容的提问来源于stack exchange,提问作者Alphatrix

