PROCEDURE 字符串语句总是返回 0
Posted
技术标签:
【中文标题】PROCEDURE 字符串语句总是返回 0【英文标题】:PROCEDURE Return always 0 for string statement 【发布时间】:2020-04-01 16:48:35 【问题描述】:我有一个可以由用户为多列动态更改的过程,我在运行它时用 SQL 编写它。在 Visual Studio 的 SQL 和 Server Explorer 中一切正常,但是当我想在 C# 中使用它并调用它时,它总是返回 0。 谁能帮帮我?!
CREATE PROCEDURE [dbo].[PDaynamicActualBy2Column]
@Colname1 nvarchar(100),
@VarCol1 nvarchar(100),
@Colname2 nvarchar(100),
@VarCol2 nvarchar(100),
@VarWeekNum nvarchar(100)
as
DECLARE @temp nvarchar(1500)
set @temp='SELECT SUM([dbo].[WeekActualTemp].[ACTUAL]) from [dbo].[MAINTB] join [dbo].[WeekActualTemp] on [dbo].[MAINTB].[UQ]=[dbo].[WeekActualTemp].[UQ]
where [dbo].[WeekActualTemp].[WeekNO]='+@VarWeekNum+' And [dbo].[MAINTB].'+@Colname1+' = '''+@VarCol1+''' And [dbo].[MAINTB].'+@Colname2+' = '''+@VarCol2+''''
exec (@temp)
【问题讨论】:
一点建议,把PRINT @temp
放在EXEC
之前。然后你可以调试正在执行的sql,也许会有什么东西跳出来。哎呀,为什么不打印正在执行的 sql 并与您的问题一起发布......那会很酷。
此过程存在安全隐患,因为它为 SQL 注入攻击打开了大门。此外,在列标识符中使用超过 2 部分是不推荐的 - 即使它不是 - 有 good reasons 为什么你应该为你的列坚持使用 2 部分标识符。阅读我题为 The do’s and don’ts of dynamic SQL for SQL Server 的博文,了解如何编写安全的动态 SQL。
我为我的专栏做一些计算的唯一方法是用户选择手册是这样的,无论如何我都知道如何解决它,但是在 c# 代码中调用这个程序时它总是返回 0跨度>
请edit您的问题包含执行该过程并尝试将值返回给c#的c#代码。
再次,请edit您的问题包含执行该过程的c#代码。
【参考方案1】:
这并没有解决 C# 中的问题,但是,它确实解决了您在代码中遇到的巨大 注入问题。如前所述,不要注入您的参数并正确引用您的动态对象名称。这会导致如下所示:
CREATE PROC dbo.PDaynamicActualBy2Column @Colname1 sysname, @VarCol1 nvarchar(100), @Colname2 sysname, @VarCol2 nvarchar(100), @VarWeekNum int AS --Assumed @VarWeekNum is an int, as why else is it called "num"?
BEGIN
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET @SQL = N'SELECT SUM(WAT.Actual) AS ActualSum' + @CRLF +
N'FROM dbo.MAINTB MTB' + @CRLF +
N' JOIN dbo.WeekActualTemp WAT ON MTB.UQ = WAT.UQ' + @CRLF +
N'WHERE WAT.WeekNO = @VarWeekNum' + @CRLF +
N' AND MTD.' + QUOTENAME(@Colname1) + N' = @VarCol1' + @CRLF +
N' AND MTD.' + QUOTENAME(@Colname2) + N' = @VarCol2;';
--PRINT @SQL; Your Best Friend
EXEC sp_executesql @SQL, N'@VarCol1 nvarchar(100),@VarCol2 nvarchar(100),@VarWeekNum int', @VarCol1, @VarCol2, @VarWeekNum;
END;
GO
因为您只返回一个标量值,您也可以使用OUTPUT
参数来代替SELECT
来显示值。如下所示:
CREATE PROC dbo.PDaynamicActualBy2Column @Colname1 sysname, @VarCol1 nvarchar(100), @Colname2 sysname, @VarCol2 nvarchar(100), @VarWeekNum int, @ActualSum int OUTPUT AS --Assumes Actual is an int in your table. Use an appropriate data type
BEGIN
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET @SQL = N'SELECT @ActualSum = SUM(WAT.Actual)' + @CRLF +
N'FROM dbo.MAINTB MTB' + @CRLF +
N' JOIN dbo.WeekActualTemp WAT ON MTB.UQ = WAT.UQ' + @CRLF +
N'WHERE WAT.WeekNO = @VarWeekNum' + @CRLF +
N' AND MTD.' + QUOTENAME(@Colname1) + N' = @VarCol1' + @CRLF +
N' AND MTD.' + QUOTENAME(@Colname2) + N' = @VarCol2;';
--PRINT @SQL; Your Best Friend
EXEC sp_executesql @SQL, N'@VarCol1 nvarchar(100),@VarCol2 nvarchar(100),@VarWeekNum int, @ActualSum int OUTPUT', @VarCol1, @VarCol2, @VarWeekNum, @ActualSum OUTPUT; --Again, assumes Actual is an int.
END;
GO
请注意,如 cmets 中所述,我去掉了为您的列命名的 3+ 部分,而是为您的表命名。然后我使用这些别名来引用正确的对象。如果您需要调试它,我还在代码中添加了“Your best Friend”。
注意:正如另一个答案中提到的,零很可能是因为 SP 返回 0
表示成功。这是存储过程的documented 和有意功能:
除非另有说明,否则所有系统存储过程都返回值 0。这表示成功,非零值表示失败。
由于上面的 SP 很可能成功,RETURN
的值为0
;来表示成功。您不应该查看 RETURN
值,而是查看数据集,或者在后一个示例中查看 OUTPUT
参数的值。我确信关于如何在 linq 中使用 OUTPUT
参数存在一些问题。
【讨论】:
【参考方案2】:您的存储过程的返回值为零表示它已成功执行。
您应该通过“RETURN”语句或“SELECT”语句为表返回一个值。
【讨论】:
即使在 Exec() 之后使用 select 也不能在 c# 代码中工作【参考方案3】:在 LINQ 中,您不能调用具有动态元输出的 SP,您必须编写带有“选择”输出的 SP 并制作模型,然后转到 SP 并再次对其进行编辑。
Alter PROCEDURE [dbo].[PDaynamicActualBy2Column]
@Colname1 nvarchar(100),
@VarCol1 nvarchar(100),
@Colname2 nvarchar(100),
@VarCol2 nvarchar(100),
@VarWeekNum nvarchar(100)
as
DECLARE @temp nvarchar(1500)
set @temp='SELECT SUM([dbo].[WeekActualTemp].[ACTUAL]) from [dbo].[MAINTB] join [dbo].[WeekActualTemp] on [dbo].[MAINTB].[UQ]=[dbo].[WeekActualTemp].[UQ]
where [dbo].[WeekActualTemp].[WeekNO]='+@VarWeekNum+' And [dbo].[MAINTB].'+@Colname1+' = '''+@VarCol1+''' And [dbo].[MAINTB].'+@Colname2+' = '''+@VarCol2+''''
-- exec (@temp)
SELECT top 0
SUM([dbo].[WeekActualTemp].[ACTUAL]) as sum
from [dbo].[MAINTB] join [dbo].[WeekActualTemp] on [dbo].[MAINTB].[UQ]=[dbo].[WeekActualTemp].[UQ]
然后在您的 LINQ 中导入 SP,然后注释“select”并取消注释“exec”。
【讨论】:
我怀疑这是因为它仍然存在一些主要的注入问题,并且仍然使用 3+ 部分命名列。出于不同的原因,这两个都是坏主意。以上是关于PROCEDURE 字符串语句总是返回 0的主要内容,如果未能解决你的问题,请参考以下文章
.net中ExecuteNonQuery方法,返回操作行数,用存储过程时,为啥总是返回-1呢