【问题标题】:PROCEDURE Return always 0 for string statementPROCEDURE 字符串语句总是返回 0
【发布时间】: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#代码。

标签: c# sql sql-server tsql stored-procedures


【解决方案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+ 部分命名列。出于不同的原因,这两个都是坏主意。
    猜你喜欢
    • 2020-10-14
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    • 2016-01-04
    • 2015-08-11
    相关资源
    最近更新 更多