Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 2005 如何在SQLServer2005中升级(更新或插入)_Sql Server 2005 - Fatal编程技术网

Sql server 2005 如何在SQLServer2005中升级(更新或插入)

Sql server 2005 如何在SQLServer2005中升级(更新或插入),sql-server-2005,Sql Server 2005,我有一个表,我在其中为员工插入行,但下一次当我要插入行时,我不想再次插入该员工的数据,只想使用所需的列进行更新,如果不存在,则创建新行 我们如何在SQLServer2005中做到这一点 我正在使用jsp 我的问题是 String sql="insert into table1(id,name,itemname,itemcatName,itemQty)values('val1','val2','val3','val4','val5')"; 如果是第一次,则将其插入数据库,如果存在,则更新它 如何

我有一个表,我在其中为员工插入行,但下一次当我要插入行时,我不想再次插入该员工的数据,只想使用所需的列进行更新,如果不存在,则创建新行

我们如何在SQLServer2005中做到这一点

我正在使用jsp

我的问题是

String sql="insert into table1(id,name,itemname,itemcatName,itemQty)values('val1','val2','val3','val4','val5')";
如果是第一次,则将其插入数据库,如果存在,则更新它


如何做?

尝试检查是否存在:

IF NOT EXISTS (SELECT * FROM dbo.Employee WHERE ID = @SomeID)

    INSERT INTO dbo.Employee(Col1, ..., ColN)
    VALUES(Val1, .., ValN)

ELSE

    UPDATE dbo.Employee
    SET Col1 = Val1, Col2 = Val2, ...., ColN = ValN
    WHERE ID = @SomeID
您可以轻松地将其封装到存储过程中,只需从外部调用该存储过程,例如从C或您正在使用的任何编程语言调用该存储过程

更新:您可以只在一个长字符串中编写整个语句,这是可行的,但不是很有用,或者您可以将其包装到存储过程中:

CREATE PROCEDURE dbo.InsertOrUpdateEmployee
       @ID INT,
       @Name VARCHAR(50),
       @ItemName VARCHAR(50),  
       @ItemCatName VARCHAR(50),
       @ItemQty DECIMAL(15,2)
AS BEGIN
    IF NOT EXISTS (SELECT * FROM dbo.Table1 WHERE ID = @ID)
       INSERT INTO dbo.Table1(ID, Name, ItemName, ItemCatName, ItemQty)
       VALUES(@ID, @Name, @ItemName, @ItemCatName, @ItemQty)
    ELSE
       UPDATE dbo.Table1
       SET Name = @Name,
           ItemName = @ItemName,
           ItemCatName = @ItemCatName,
           ItemQty = @ItemQty
       WHERE ID = @ID
END
然后只需从ADO.NET代码调用该存储过程,就可以使用表上的INSTEAD OF INSERT触发器执行此操作,该触发器检查行的存在性,然后根据行是否已存在更新/插入。有一个示例说明如何在MSDN上为SQL Server 2000+执行此操作:

您可以使用@ROWCOUNT检查是否应插入或更新行:

update table1 
set name = 'val2', itemname = 'val3', itemcatName = 'val4', itemQty = 'val5'
where id = 'val1'
if @@ROWCOUNT = 0
insert into table1(id, name, itemname, itemcatName, itemQty)
values('val1', 'val2', 'val3', 'val4', 'val5')

在这种情况下,如果更新失败,将插入新行。您可以检查该行是否存在,然后插入或更新,但这保证您将执行两个SQL操作,而不是一个SQL操作:

检查行是否存在 插入或更新行 更好的解决方案是始终先更新,如果没有更新行,则执行插入,如下所示:

update table1 
set name = 'val2', itemname = 'val3', itemcatName = 'val4', itemQty = 'val5'
where id = 'val1'

if @@ROWCOUNT = 0
  insert into table1(id, name, itemname, itemcatName, itemQty)
  values('val1', 'val2', 'val3', 'val4', 'val5')
这将执行一个SQL操作,或两个SQL操作,具体取决于行是否已存在

但是,如果性能确实是一个问题,那么您需要确定操作更可能是INSERT操作还是UPDATE操作。如果更新更常见,请执行上述操作。如果INSERT更常见,则可以反向执行,但必须添加错误处理

BEGIN TRY
  insert into table1(id, name, itemname, itemcatName, itemQty)
  values('val1', 'val2', 'val3', 'val4', 'val5')
END TRY
BEGIN CATCH
  update table1 
  set name = 'val2', itemname = 'val3', itemcatName = 'val4', itemQty = 'val5'
  where id = 'val1'
END CATCH
要真正确定是否需要执行更新或插入,必须在一个事务中执行两个操作。理论上,就在第一次更新或INSERT甚至EXISTS检查之后,但在下一个INSERT/UPDATE语句之前,数据库可能已经更改,导致第二个语句仍然失败。这是非常罕见的,交易的开销可能不值得

或者,您可以使用一个名为MERGE的SQL操作来执行插入或更新,但对于这一行操作来说,这也可能是一种过分的操作


请考虑阅读有关的文章。

这里是Michael J.Swart关于这一问题的一篇有用的文章,其中介绍了在SQL Server中实现UPSERT的不同模式和反模式:

它解决了相关的并发性问题—主键冲突、死锁—本文中提供的所有答案都被认为是反模式,但使用触发器的@Bridge解决方案除外,这里没有介绍

以下是文章的摘录,以及作者首选的解决方案:

在带有锁提示的可序列化事务中:

CREATE PROCEDURE s_AccountDetails_Upsert ( @Email nvarchar(4000), @Etc nvarchar(max) )
AS 
  SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  BEGIN TRAN

    IF EXISTS ( SELECT * FROM dbo.AccountDetails WITH (UPDLOCK) WHERE Email = @Email )

      UPDATE dbo.AccountDetails
         SET Etc = @Etc
       WHERE Email = @Email;

    ELSE 

      INSERT dbo.AccountDetails ( Email, Etc )
      VALUES ( @Email, @Etc );

  COMMIT

在stackoverflow上还有一个相关的问题和答案:

在哪里用上面的sql字符串写上面的代码,或者需要创建触发器或过程。用单个字符串写它看起来像字符串sql=如果不存在,从Employee中选择*,其中ID=@someidINSERT到Employee col1,…,colNvaluesval1,…,valNELSE更新Employee SET col1=val1,col2=val2,…,colN=valN,其中ID=@someID将执行此操作。@ybc126:如果SQL中有必要的空格-是。但这样的事情绝对不可取!将其放入存储过程或使用ORM处理会更好。通常建议不要使用Select*from。我不知道使用if not EXISTS SELECT*FROM时是否重要。。。但我可能会使用如果不存在选择Id从。。。只是为了避免使用*。我正确地假设存储过程不会处理并发请求。如果两个请求同时访问并试图插入相同的主键,而主键在表中尚不存在,则两个请求将同时通过第一个条件,因为select可以并行运行。但是,INSERT需要在exclusion中运行,因此其中一个查询将添加新记录,而另一个查询将出现异常,表明存在重复的主键。将MERGE子句与它一起使用一个包含用户详细信息的临时表如何?这不是更好吗?Sakhile-是的-那么你的答案在哪里。。。答复第?节?合并适用于此用例,但应注意,它仅在SQL Server 2008中引入,大概六年后OP不再使用2005。指向您提到的问题的链接特定于MySql,因为此线程是关于SQL Server的,而SQL Server没有重复密钥更新选项。你能告诉我克莱尔吗
请告诉我你的意思是什么,或者这是你的错误?这应该被接受,因为这是最有效的答案。它不会搜索两次更新
CREATE PROCEDURE s_AccountDetails_Upsert ( @Email nvarchar(4000), @Etc nvarchar(max) )
AS 
  SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  BEGIN TRAN

    IF EXISTS ( SELECT * FROM dbo.AccountDetails WITH (UPDLOCK) WHERE Email = @Email )

      UPDATE dbo.AccountDetails
         SET Etc = @Etc
       WHERE Email = @Email;

    ELSE 

      INSERT dbo.AccountDetails ( Email, Etc )
      VALUES ( @Email, @Etc );

  COMMIT