存储过程MERGE(INSERT OR UPDATE)和返回ID问题

时间:2014-05-25 21:41:50

标签: c# stored-procedures

所以我正在尝试学习如何使用存储过程,并且在很大程度上我有点理解除了这个合并过程之外如何使用它们。

我想要做的是使用MERGE过程插入如果一行尚不存在并返回ID ELSE IF NOT EXISTS然后只返回ID。

目前这是我目前所拥有的。

CREATE PROCEDURE dbo.authors_InsertOrUpdate
-- Add the parameters for the stored procedure here
@FirstName nvarchar(50), 
@LastName nvarchar(50),
@id int = NULL OUTPUT
AS
MERGE Authors AS target
USING (SELECT @FirstName, @LastName) AS source (FirstName, LastName)
ON target.FirstName = source.FirstName AND target.LastName = source.LastName
WHEN MATCHED THEN
    UPDATE 
    SET @id = SCOPE_IDENTITY()
WHEN NOT MATCHED THEN INSERT 
    (FirstName, LastName) VALUES (source.FirstName, source.LastName);
    SET @id = SCOPE_IDENTITY()

就将值/信息输入数据库并查找现有数据而言,一切正常,但我没有正确地恢复我的ID值。这是我使用它的方法..

private static int storeAuthors(string firstName, string lastName)
        {
            String commandText = "dbo.authors_InsertOrUpdate";
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["AmazonCrawler.Properties.Settings.database"].ToString()))
            {
                using (SqlCommand command = new SqlCommand(commandText, connection))
                {
                    command.CommandType = CommandType.StoredProcedure;
                    command.Parameters.Add(new SqlParameter("@FirstName", firstName));
                    command.Parameters.Add(new SqlParameter("@LastName", lastName));
                    SqlParameter authorId = new SqlParameter("@id", SqlDbType.Int);
                    authorId.Direction = ParameterDirection.Output;
                    command.Parameters.Add(authorId);

                    connection.Open();
                    command.ExecuteNonQuery();
                    connection.Close();

                    return Convert.ToInt32(authorId.Value);
                }
            }
        }

请帮我解决这个问题!

提前致谢。

--------- EDIT ------------

更新了此过程,但当我尝试返回值时,我仍然在代码中收到空值

CREATE PROCEDURE dbo.authors_InsertOrUpdate
    -- Add the parameters for the stored procedure here
    @FirstName nvarchar(50), 
    @LastName nvarchar(50),
    @id int OUTPUT
AS
MERGE Authors AS target
USING (SELECT @id, @FirstName, @LastName) AS source (id, FirstName, LastName)
ON target.FirstName = source.FirstName AND target.LastName = source.LastName
WHEN NOT MATCHED THEN 
    INSERT (FirstName, LastName) VALUES (source.FirstName, source.LastName);
    SET @id = SCOPE_IDENTITY()

编辑参考1 enter image description here

编辑参考2

enter image description here

编辑参考3

ALTER PROCEDURE dbo.authors_InsertOrUpdate
    -- Add the parameters for the stored procedure here
    @FirstName nvarchar(50), 
    @LastName nvarchar(50),
    @id int OUTPUT

AS
MERGE Authors AS target
USING (SELECT @id, @FirstName, @LastName) AS source (ID, FirstName, LastName)
ON target.FirstName = source.FirstName AND target.LastName = source.LastName
WHEN MATCHED THEN 
    UPDATE SET @id = target.ID
WHEN NOT MATCHED THEN 
    INSERT (FirstName, LastName) VALUES (source.FirstName, source.LastName);
    SET @id = SCOPE_IDENTITY()

SELECT @id

仍然收到参考文献2中列出的相同错误。 =(还没有解决方案。

这是我传入的值,返回零作为id enter image description here

这是我的数据库

enter image description here

编辑参考4

尝试在将值添加到此时更改我的参数,因为我认为在获取值之前关闭它会导致问题但没有运气

private static int storeAuthors(string firstName, string lastName)
        {
            String commandText = "dbo.authors_InsertOrUpdate";
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["AmazonCrawler.Properties.Settings.database"].ToString()))
            {
                using (SqlCommand command = new SqlCommand(commandText, connection))
                {
                    command.CommandType = CommandType.StoredProcedure;
                    command.Parameters.Add(new SqlParameter("@FirstName", firstName));
                    command.Parameters.Add(new SqlParameter("@LastName", lastName));
                    SqlParameter authorId = new SqlParameter("@id", SqlDbType.Int);
                    authorId.Direction = ParameterDirection.Output;
                    command.Parameters.Add(authorId);

                    connection.Open();
                    command.ExecuteNonQuery();
                    int value = Convert.ToInt32(authorId.Value);
                    connection.Close();

                    return value;
                }
            }
        }

2 个答案:

答案 0 :(得分:1)

在UPDATE情况下,您不会生成新的IDENTITY,您只是查询,因此SCOPE_IDENTITY()不会返回正确的值。在UPDATE的情况下,SCOPE_IDENTITY()似乎可能起作用,但它实际上是从范围内的最后一个INSERT返回值(我认为),这可能是存储过程的最后一次执行。

我建议使用OUTPUT子句。我尝试用你的方法制作一些东西,并且使用@ usr的建议,但我唯一能做的工作就是使用OUTPUT子句。见下文:

CREATE PROCEDURE dbo.authors_InsertOrUpdate
    -- Add the parameters for the stored procedure here
    @FirstName nvarchar(50), 
    @LastName nvarchar(50),
    @id int OUTPUT
AS BEGIN
   DECLARE @MergeOutput table
   ( 
     ACTION VARCHAR(10),
     ID INT
   );

   MERGE Authors AS target
     USING (SELECT @id, @FirstName, @LastName) AS source (id, FirstName, LastName)
       ON target.FirstName = source.FirstName AND target.LastName = source.LastName
     WHEN NOT MATCHED THEN
       INSERT (FirstName, LastName) VALUES (source.FirstName, source.LastName)
     WHEN MATCHED THEN UPDATE
       SET @Id = target.Id
     OUTPUT $action, INSERTED.ID INTO @MergeOutput;

   SELECT @Id = Id FROM @MergeOutput

END
GO

DECLARE @id2 INT
exec dbo.authors_InsertOrUpdate 'Melvin', 'Smith', @id = @id2 OUTPUT
SELECT @id2
GO

我尝试使用SCOPE_IDENTITY()创建一些工作,并使用SET @Id = target.Id,就像在@usr的答案中一样,但我仍然会返回最后插入的值,即使是更新。

答案 1 :(得分:1)

SELECT * INTO #o FROM sys.objects

DECLARE @id INT

MERGE #o AS target
USING (SELECT OBJECT_ID('tempdb..#o') AS object_id) AS source (object_id)
ON target.object_id = source.object_id
WHEN MATCHED THEN UPDATE SET @id = target.object_id;

SELECT @id

您可以非常自由地使用MERGE查询的列。这是一个非常有力的声明。