Sql server 如何在SQL Server数据库中创建和使用“out”参数
我正在开发一个C桌面应用程序。我想使用存储过程insert查询将新记录添加到数据表中。我需要返回主键,它是一个identity insert bigint,以避免再次往返数据库。我在MS文件中搜索了几个小时,没有找到任何关于如何设置存储过程的out参数或如何获取返回值的信息。您需要的是一个输出参数。我不是C开发人员,所以我省略了C方面的内容,并链接了一个答案:Sql server 如何在SQL Server数据库中创建和使用“out”参数,sql-server,Sql Server,我正在开发一个C桌面应用程序。我想使用存储过程insert查询将新记录添加到数据表中。我需要返回主键,它是一个identity insert bigint,以避免再次往返数据库。我在MS文件中搜索了几个小时,没有找到任何关于如何设置存储过程的out参数或如何获取返回值的信息。您需要的是一个输出参数。我不是C开发人员,所以我省略了C方面的内容,并链接了一个答案: --Sample Table CREATE TABLE dbo.YourTable (ID bigint IDENTITY,
--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;
用这个,我认为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;
我的印象是你正试图通过三次往返旅行,如下所示:
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();
}
只需注意存储过程本身是否有任何未解析的select查询,在这种情况下,您需要使用ExecuteReader及其NextResult方法在select查询结果之间前进
当然,这可能比实际代码更重要,您需要插入新数据的参数,但这提供了一般概念。在insert上使用OUTPUT子句非常好,如果您需要在多行批处理中捕获标识值,那么这是非常必要的。然而,对于SQL初学者来说,代码稍微复杂一些,对于这个特定的问题,它可能会与存储过程的输出参数混淆,这是一个完全不相关的概念 但是,对于单行插入,该函数非常有效,而且使用起来更简单 以下是使用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;
在你们的帮助下,我终于明白了。我对存储过程进行了如下修改: //存储过程
使用存储过程而不是直接执行INSERT有什么原因吗?使用函数而不是过程,可以使用返回值。Dai,存储过程更快,有助于防范sql注入攻击。不是万无一失的,但它有帮助。存储过程并不比其他类型的查询快。这是一个经常被引用的神话。参数化查询可以防止注入攻击。您不需要使用存储过程来实现这一点。这很酷,但它没有回答如何使用存储过程的输出参数的问题。这是最有帮助的,让我能够找到答案。下面我的答案中适用于我的代码。谢谢你给我指出了正确的方向。欢迎@user1818434,请将其标记为答案,以便将来的读者知道答案是有用的。此外,你还因为把一个问题作为答案而名声大噪。
```` -- 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;
````}