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的主要内容,如果未能解决你的问题,请参考以下文章

Procedure 存储过程

.net中ExecuteNonQuery方法,返回操作行数,用存储过程时,为啥总是返回-1呢

MySQL数据库(31):存储过程 procedure

HSQL - 意外的令牌:语句中的 PROCEDURE

PHP PDO Update语句总是返回0行受影响的rowCount()

JSON .count 数组在 Swift 4 中总是返回 0