如何在SQL Server数据库中创建和使用“输出”参数

时间:2019-05-30 14:02:33

标签: sql-server

我正在使用C#桌面应用程序。我想使用存储过程(插入查询)将新记录添加到数据表中。我需要返回主键,该主键是一个身份插入(bigint),以避免再次往返数据库。我已经搜索了几个小时的MS Help(less)文件,却发现如何设置存储过程的out参数或如何获取返回值一无所获。

4 个答案:

答案 0 :(得分:1)

您想要的是一个OUTPUT参数。我不是C#开发人员,因此我省略了C#方面,并链接了一个答案:

--Sample Table
CREATE TABLE dbo.YourTable (ID bigint IDENTITY,
                            SomeColumn varchar(20));

GO
--Sample SP
CREATE PROC dbo.InsertYourTable @SomeColumn varchar(20), @ID bigint OUTPUT AS
BEGIN

    DECLARE @IDt table (ID bigint);

    INSERT INTO dbo.YourTable(SomeColumn)
    OUTPUT inserted.ID INTO @IDt
    VALUES(@SomeColumn);

    SET @ID = (SELECT ID FROM @IDt);
END;

GO
--Sample EXEC of proc and PRINT of OUTPUT value of ID
DECLARE @SomeColumn varchar(20) = 'abc', @ID bigint;

EXEC dbo.InsertYourTable @SomeColumn = @SomeColumn,
                         @ID = @ID OUTPUT;

PRINT @ID;

使用此answer,我认为c#将是:

cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@SomeColumn",SqlDbType.VarChar,20);
cmd.Parameters["@SomeColumn"].Value = MyColumn;
cmd.Parameters.Add("@ID",SqlDbType.int).Direction = ParameterDirection.Output;

答案 1 :(得分:0)

给我的印象是您正试图从三个往返行程中走出来,像这样:

INSERT => SELECT to get key => OTHER INSERT using previous key

到两个

INSERT returns the key => OTHER INSERT using previous key

我们可以做得更好。

解决此问题的一种方法是在C#中的sql字符串中发送多个命令。因此,您最终得到了这样的结果,该结果达到了避免对数据库进行额外往返的目的:

string sql = @"
   DECLARE @ID int; 
   EXEC InsertProcedure; 
   SELECT @ID = scope_identity(); 
   INSERT INTO OtherTable VALUES (@ID);";

using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
    cn.Open();
    cmd.ExecuteNonQuery();
}

或者,也许您只想在应用程序中使用该键,因此您可以继续使用记录并通过该新的聚集索引值进行快速查找。在这种情况下,您仍然可以这样:

string sql = @"
   DECLARE @ID int; 
   EXEC InsertProcedure; 
   SELECT scope_identity();";

using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
    cn.Open();
    return (int)cmd.ExecuteScalar();
}

请务必小心,存储过程本身是否有任何未解决的选择查询,在这种情况下,您需要使用ExecuteReader()以及NextResult()方法在{{1}之间进行切换}查询结果。

当然,它可能比实际代码要多得多,在实际代码中,您需要插入新数据的参数,但这提供了一般概念。

答案 2 :(得分:0)

在INSERT上使用OUTPUT子句很棒,如果需要捕获多行批处理中的标识值,则必不可少。但是,对于SQL初学者来说,代码要复杂一些,对于这个特定的问题,它可能与存储过程的OUTPUT parameter 混淆,这是一个完全无关的概念。

但是对于单行插入,SCOPE_IDENTITY函数可以很好地工作并且易于使用。

以下是Larnu's stored proc的一个版本,使用的是SCOPE_IDENTITY:

CREATE PROC dbo.InsertYourTable @SomeColumn varchar(20), @ID bigint OUTPUT AS
BEGIN

INSERT INTO dbo.YourTable(SomeColumn)
VALUES(@SomeColumn);

SET @ID = SCOPE_IDENTITY();
END;

答案 3 :(得分:0)

在大家的帮助下,我终于弄清楚了。我修改了存储过程,如下所示:


//存储过程

```` -- Add the parameters for the stored procedure here
````@Vendorcode nvarchar(17) = ''
````, @Name nvarchar(60) = ''
````...
````, @ID bigint output  --<<<<<<<<Added this line
````AS
````BEGIN
````    -- SET NOCOUNT ON added to prevent extra result sets from
````    -- interfering with SELECT statements.
````    SET NOCOUNT ON;
````    -- Insert statements for procedure here
````INSERT INTO APVendorShipTo
````        (Vendorcode, [Name], ...)
````VALUES  (@Vendorcode, @Name,...)

````Select @ID = SCOPE_IDENTITY(); -- <<<<<<<< Added this line
````END
*//end Stored Procedure*
----------


----------

*//C# Code in Desktop App*

````try
````{
````string connString = AdoHelper.ConnectionString;
````var myConnection = new SqlConnection(connString);
````var myCommand = new SqlCommand();
````using (myConnection)
````{
```` myConnection.Open();
```` myCommand.Connection = myConnection;
```` myCommand.CommandType = CommandType.StoredProcedure;
```` myCommand.CommandTimeout = 540;
```` myCommand.CommandText = "APVendorShipToAddNew";     
```` myCommand.Parameters.AddWithValue(parameterName: "@Vendorcode", value:   
this.txtAcctNo.Text);
```` myCommand.Parameters.AddWithValue(parameterName: "@Name", value: this.txtShipName.Text);
-- left out the rest of the parameters
--//Added the line below to retrieve the Identity Insert value from the query
````myCommand.Parameters.Add("@ID", SqlDbType.BigInt).Direction = ParameterDirection.Output;

````myCommand.ExecuteNonQuery();

--//Added next line to convert the returned value to a usable value in my program.
````liID = Convert.ToInt64(myCommand.Parameters["@ID"].Value);

````MessageBox.Show(Convert.ToString(liID)); 
--//Showed correct value Now available to  my code

````return true;
````}