【问题标题】:Can I Assign a variable in a SQL Stored Procedure?我可以在 SQL 存储过程中分配变量吗?
【发布时间】:2011-02-04 20:33:15
【问题描述】:

我正在执行 SQL 插入来填充我的表。我在一个表中有一个唯一生成的 ID,我想在另一个表中使用它来进行联接。这可能吗?

.NET MVC --

using (SqlConnection connect = new SqlConnection(connections))
{
    SqlCommand command = new SqlCommand("ContactInfo_Add", connect);
    command.Parameters.Add(new SqlParameter("name", name));
    command.Parameters.Add(new SqlParameter("address", address));
    command.Parameters.Add(new SqlParameter("Product", name));
    command.Parameters.Add(new SqlParameter("Quantity", address));
    command.Parameters.Add(new SqlParameter("DueDate", city));
    connect.Open();
    command.ExecuteNonQuery();
}

SQL 服务器 --

ALTER PROCEDURE [dbo].[Contact_Add]
@name varchar(40),
@address varchar(60),
@Product varchar(40),
@Quantity varchar(5),
@DueDate datetime
AS 
BEGIN
     SET NOCOUNT ON;

     INSERT INTO DBO.PERSON
     (Name, Address) VALUES (@name, @address)
     INSERT INTO DBO.PRODUCT_DATA
     (PersonID, Product, Quantity, DueDate) VALUES (@Product, @Quantity, @DueDate)
END

代码插入正常。我该如何提取自动生成的 PersonID 以在 PRODUCT_DATA 中使用?

【问题讨论】:

  • user54197 查看 KM 的回答和我对此的评论。如果有人在不知不觉中更改了您的存储过程,则使用 Scope Identity 返回 PersonID 存在一些潜在问题。
  • @msarchet:想详细说明这些潜在问题是什么?当然,如果有人在不知道它是如何工作的情况下更改它,他们可能会破坏您的存储过程,但这与 SCOPE_IDENTITY 本身无关 - 他们很可能会破坏 OUTPUT INSERTED 子句。
  • 正如您刚才所说,这不是 SCOPE_IDENTITY 本身的问题,效果很好。使用插入的输出更加确定,因为如果有人更改存储过程的顺序,它不会中断。这并不完美,因为显然有人总是会破坏您的 SP,无论您如何返回值。使用像@variable int output 这样的参数是获取输出的最明显方法。但是仍然有人可以打破它,但这仍然更难。
  • 在我使用 SQL Server 的所有时间里(十年了,真遗憾!),我从未见过有人更改存储过程以获取错误的 scope_identity。我想这可能会发生,但通常我不会让任何不知道自己在做什么的人编写 proc。但是,如果您拥有较新版本的 SQl Server,则输出子句是更好的选择,原因有很多,包括您可以返回一个不是通过标识生成的值,甚至可以返回一个以上的值。

标签: sql mysql sql-server stored-procedures


【解决方案1】:

您无需使用 SCOPE_IDENTITY(),只需使用 OUTPUT 和单个 INSERT 语句!
这确实需要 SQL Server 2005 及更高版本

试试这个:

设置表格

CREATE TABLE Test1 (PersonID int identity(1,1), Name varchar(40), Address varchar(60))
CREATE TABLE Test2 (PersonID int, product varchar(40),Quantity varchar(5),DueDate datetime)

创建过程

CREATE PROCEDURE TestSP
@name varchar(40),
@address varchar(60),
@Product varchar(40),
@Quantity varchar(5),
@DueDate datetime
AS 
BEGIN
     SET NOCOUNT ON;

     INSERT INTO Test1
             (Name, Address)
             OUTPUT INSERTED.PersonID, @Product, @Quantity, @DueDate
             INTO Test2
         VALUES 
             (@name, @address)

END

测试代码

exec TestSP 'name','address','product',123,'1/1/2010'
select * from Test1
select * from Test2

输出

PersonID    Name                 Address
----------- -------------------- -----------------------
1           name                 address

(1 row(s) affected)

PersonID    product   Quantity DueDate
----------- --------- -------- -----------------------
1           product   123      2010-01-01 00:00:00.000

(1 row(s) affected)

【讨论】:

  • 同意使用范围标识有效,直到有人更改您的存储过程导致返回的最后一个值不是正确的。哎呀
  • 这是一种将项目添加到日志表的简单方法。您甚至可以一次拥有多个 OUTPUT 语句。此外,如果您删除 INTO,它会返回一个结果集。例如将OUTPUT INSERTED.* 放在INTO Test2VALUES 之间。当您运行 TestSP 过程时,它将插入到两个表中并返回一个包含 Test1 表的结果集(两个INSERTs 和一个SELECT 在一个INSERT 中!)。
【解决方案2】:

您可以使用SCOPE_IDENTITY 获取最后插入的标识值:

DECLARE @PersonID INT

INSERT INTO dbo.Person (Name, Address)
VALUES (@Name, @Address)

SET @PersonID = SCOPE_IDENTITY()

INSERT INTO dbo.Product_Data (PersonID, Product, Quantity, DueDate)
VALUES (@PersonID, @Product, @Quantity, @DueDate)

【讨论】:

  • 您可以在不使用 SCOPE_IDENTITY() 的情况下插入两个表,并在单个 INSERT 语句中查看我的答案:stackoverflow.com/questions/2585723/…
  • @KM:我知道您可以使用 OUTPUT INSERTED 子句通过单个语句来完成。一般来说,我发现单独的语句更具可读性/可维护性:每件工作都有一个语句。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
  • 2020-04-03
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 2011-07-16
  • 2016-01-04
相关资源
最近更新 更多