将 Int 传递给动态存储过程失败
Passing Int to dynamic stored procedure fails
我在 SQL 服务器中有一个动态存储过程,可以很好地转换 table:
CREATE PROCEDURE dbo.DynamicPivotTableInSql
@ColumnToPivot NVARCHAR(255),
@ListToPivot NVARCHAR(255),
@SurveyID INT=10
AS
BEGIN
DECLARE @SqlStatement NVARCHAR(MAX)
SET @SqlStatement = N'SELECT *
FROM
(SELECT
[resp_id], [benefit], [weight]
FROM Segment_Responses) myResults
PIVOT
(SUM([weight])
FOR [' + @ColumnToPivot + ']
IN (' + @ListToPivot + ')) AS PivotTable';
EXEC (@SqlStatement)
END
我这样称呼它
EXEC DynamicPivotTableInSql
@ColumnToPivot = 'benefit',
@ListToPivot = '[OBSERVABILITY], [COST], [EASE OF USE], [SERVICE]'
这是我 运行 遇到问题的地方。您会注意到我已经对 @SurveyID = 10
进行了硬编码,如果我尝试将其添加为存储过程中的 where 语句,如下所示:
FROM Segment_Responses
WHERE survey_id = ' + @SurveyID + '
和 运行 存储过程再次出现此错误:
Conversion failed when converting the nvarchar value '
SELECT * FROM (
SELECT
[resp_id],
[benefit],
[weight]
FROM Segment_Responses where survey_id=' to data type int.
我尝试了很多方法来解决这个问题(例如,传递 Int 变量而不是对其进行硬编码)但总是得到相同的结果。有什么想法吗?
+
仅适用于字符串。如果您使用数字,TSQL 会假定您正在尝试使用加法运算符,并尝试将字符串参数转换为 int。
例如这个
select 1 + '2'
有效并且returns 3.
对整数使用 CONCAT instead of +
, or use an explicit conversion。
例如
WHERE survey_id = ' + cast(@SurveyID as varchar(20)) + '
这就是为什么强烈建议不要使用语法 EXEC (@SQL)
的原因。使用 sys.sp_executesql
并参数化您的语句:
SET @SQL = N'SELECT ...
FROM ...
WHERE survey_id = @SurveyID ...;';
EXEC sys.sp_executesql @SQL, N'@SurveyID int',SurveyID;
只是为了说明一些问题,当您将两种不同的类型相加时,SQL 服务器将(在可能的情况下)隐式地将一种类型转换为另一种类型 - 毕竟结果必须是一种类型。
它根据 order of precedence 决定将哪个“转换为另一个”。
因此,当您尝试将 varchar 与 int 连接时,int具有更高的优先顺序。当在表达式的不同执行路径中混合类型时,这也是使用 case 表达式 时出现错误和错误的常见原因。
您需要显式地将 int 转换为 varchar。
理想情况下,您会使用 参数化查询,它也会重用缓存的执行计划 - 如果数据的基数相似但有时使值成为动态查询可能是有利的,这取决于用例。
我在 SQL 服务器中有一个动态存储过程,可以很好地转换 table:
CREATE PROCEDURE dbo.DynamicPivotTableInSql
@ColumnToPivot NVARCHAR(255),
@ListToPivot NVARCHAR(255),
@SurveyID INT=10
AS
BEGIN
DECLARE @SqlStatement NVARCHAR(MAX)
SET @SqlStatement = N'SELECT *
FROM
(SELECT
[resp_id], [benefit], [weight]
FROM Segment_Responses) myResults
PIVOT
(SUM([weight])
FOR [' + @ColumnToPivot + ']
IN (' + @ListToPivot + ')) AS PivotTable';
EXEC (@SqlStatement)
END
我这样称呼它
EXEC DynamicPivotTableInSql
@ColumnToPivot = 'benefit',
@ListToPivot = '[OBSERVABILITY], [COST], [EASE OF USE], [SERVICE]'
这是我 运行 遇到问题的地方。您会注意到我已经对 @SurveyID = 10
进行了硬编码,如果我尝试将其添加为存储过程中的 where 语句,如下所示:
FROM Segment_Responses
WHERE survey_id = ' + @SurveyID + '
和 运行 存储过程再次出现此错误:
Conversion failed when converting the nvarchar value ' SELECT * FROM ( SELECT [resp_id], [benefit], [weight] FROM Segment_Responses where survey_id=' to data type int.
我尝试了很多方法来解决这个问题(例如,传递 Int 变量而不是对其进行硬编码)但总是得到相同的结果。有什么想法吗?
+
仅适用于字符串。如果您使用数字,TSQL 会假定您正在尝试使用加法运算符,并尝试将字符串参数转换为 int。
例如这个
select 1 + '2'
有效并且returns 3.
对整数使用 CONCAT instead of +
, or use an explicit conversion。
例如
WHERE survey_id = ' + cast(@SurveyID as varchar(20)) + '
这就是为什么强烈建议不要使用语法 EXEC (@SQL)
的原因。使用 sys.sp_executesql
并参数化您的语句:
SET @SQL = N'SELECT ...
FROM ...
WHERE survey_id = @SurveyID ...;';
EXEC sys.sp_executesql @SQL, N'@SurveyID int',SurveyID;
只是为了说明一些问题,当您将两种不同的类型相加时,SQL 服务器将(在可能的情况下)隐式地将一种类型转换为另一种类型 - 毕竟结果必须是一种类型。
它根据 order of precedence 决定将哪个“转换为另一个”。
因此,当您尝试将 varchar 与 int 连接时,int具有更高的优先顺序。当在表达式的不同执行路径中混合类型时,这也是使用 case 表达式 时出现错误和错误的常见原因。
您需要显式地将 int 转换为 varchar。
理想情况下,您会使用 参数化查询,它也会重用缓存的执行计划 - 如果数据的基数相似但有时使值成为动态查询可能是有利的,这取决于用例。