结合INSERT和UPDATE语句(SQL2005存储过程)

时间:2009-08-10 16:36:02

标签: sql sql-server sql-server-2005 tsql stored-procedures

我需要从表中提取记录,将数据复制到第二个表,然后更新第一个表中的记录,以表明它们已成功复制。

我目前的SP代码是:

SELECT TBL_ADDRESSBOOKADDRESSES.* FROM TBL_ADDRESSBOOKADDRESSES 
INNER JOIN TBL_CAMPAIGNS
ON TBL_ADDRESSBOOKADDRESSES.adds_ABMId = TBL_CAMPAIGNS.campaign_AddressBook
WHERE TBL_CAMPAIGNS.campaign_Status = 1

现在执行上述操作后,我需要将此数据插入名为TBL_RECIPIENTS的第二个表中。假设这些列在TBL_ADDRESSBOOKADDRESSES中简单地命名为col_1,col_2,col_3 .... col_5,并且在TBL_RECIPIENTS中它们是相同的。

执行此操作后,我需要更新 TBL_CAMPAIGNS.campaign_Status = 2 理想情况下,这应仅适用于那些实际已更新的记录(如果脚本因服务器崩溃而中途停止等)

如果您需要澄清任何内容,请与我们联系。

非常感谢!


我已经采取了下面的建议,并提出下面的工作代码。我已阅读教程,建议添加try / catch以确保在发生任何错误时回滚。我的代码在这方面是否足够?

任何建议都会感激不尽。

感谢。

CREATE PROCEDURE web.SERVER_create_email_recipients
AS
BEGIN TRY
  --sets (n) campaigns ready for transfer of emails to mailing list
      UPDATE TOP(1) TBL_CAMPAIGNS
  SET TBL_CAMPAIGNS.campaign_Status = 1
  WHERE TBL_CAMPAIGNS.campaign_Status = 0

  --finds above marked campaigns, retreives addresses then copies them to     TBL_CAMPAIGNRECIPIENTS ready for auto mailout
  INSERT TBL_CAMPAIGNRECIPIENTS (recip_CampaignId, recip_Email, recip_Forename, recip_Surname, recip_adds_Key)
  SELECT C.Campaign_AddressBook, ABA.adds_Email, ABA.adds_RecipientForename,     ABA.adds_RecipientSurname, ABA.adds_Key
  FROM TBL_ADDRESSBOOKADDRESSES ABA
  JOIN TBL_CAMPAIGNS C ON ABA.adds_ABMId = C.campaign_AddressBook
  WHERE C.campaign_Status = 1

  --checks that above emails have been copied across and then sets the campaigns status accordingly
  UPDATE C
  SET C.campaign_Status = 2
  From TBL_CAMPAIGNS C
  JOIN TBL_ADDRESSBOOKADDRESSES  aba
  ON aba.adds_ABMId = C.campaign_AddressBook
  JOIN TBL_CAMPAIGNRECIPIENTS r on aba.adds_Key = r.recip_adds_Key
  WHERE C.campaign_Status = 1

END TRY
BEGIN CATCH
  -- Whoops, there was an error
  IF @@TRANCOUNT > 0
     ROLLBACK

  -- Raise an error with the details of the exception
  DECLARE @ErrMsg nvarchar(4000), @ErrSeverity int
  SELECT @ErrMsg = ERROR_MESSAGE(),
         @ErrSeverity = ERROR_SEVERITY()

  --throws out error to logs?
  RAISERROR(@ErrMsg, @ErrSeverity, 1)
END CATCH

4 个答案:

答案 0 :(得分:4)

您是否考虑将所有内容都放在交易中?

实施例: DECLARE @ErrorCode INT

BEGIN TRAN
  UPDATE Authors
  SET Phone = '911'
  WHERE au_id = 2

  SELECT @ErrorCode = @@ERROR
  IF (@intErrorCode <> 0) GOTO ErrExit

  DELETE Authors WHERE Phone = '911' au_id <> 2 

  SELECT @ErrorCode = @@ERROR
  IF @ErrorCode <> 0) GOTO ErrExit
COMMIT TRAN

ErrExit;
IF (@intErrorCode <> 0) 

ROLLBACK TRAN

如果更新或删除错误,则将回滚事务。如果系统在提交之前崩溃,则sql server会进行回滚,因为存在未公开的事务

答案 1 :(得分:2)

我对你的结构做了一些猜测,连接可能不正确

INSERT TBL_RECIPIENTS (Col1, Col2, COl3)
SELECT ABA.Col1, ABA.Col2,ABA.Col3
FROM TBL_ADDRESSBOOKADDRESSES ABA
INNER JOIN TBL_CAMPAIGNS C ON ABA.adds_ABMId = C.campaign_AddressBook
WHERE TBL_CAMPAIGNS.campaign_Status = 1

UPDATE C
SET C.campaign_Status = 2
From TBL_CAMPAIGNS C
JOIN TBL_ADDRESSBOOKADDRESSES  aba
 on aba.adds_ABMId = C.campaign_AddressBook
JOIN TBL_RECIPIENTS r on aba.id = r.sameid
WHERE TBL_CAMPAIGNS.campaign_Status = 1

注意我没有使用select *,它永远不会在生产代码中使用。我还使用了别名来使代码更容易阅读。

答案 2 :(得分:1)

一种方法是使用OUTPUT子句;在这种情况下,您可以选择已插入的所有地址簿ID,并使用它来更新广告系列。尽管如此,如果你想要获得可靠性,你真的需要使用交易,锁定会阻止更新和插入

DECLARE @addressBookIds TABLE(AddressBookId INT NOT NULL)

INSERT INTO TBL_RECIPIENTS
OUTPUT INSERTED.adds_ABMId INTO @addressBookIds
SELECT TBL_ADDRESSBOOKADDRESSES.* 
FROM   TBL_ADDRESSBOOKADDRESSES
INNER JOIN TBL_CAMPAIGNS
  ON   TBL_ADDRESSBOOKADDRESSES.adds_ABMId = TBL_CAMPAIGNS.campaign_AddressBook
WHERE  TBL_CAMPAIGNS.campaign_Status = 1

UPDATE TBL_CAMPAIGNS
SET [campaign_Status] = 2
FROM TBL_CAMPAIGNS
INNER JOIN @addressBookIds AS T
ON TBL_CAMPAIGNS.campaign_AddressBook = T.AddressBookId
AND TBL_CAMPAIGNS.campaign_Status = 1

如果广告系列ID是TBL_RECIPIENTS表的一部分,那么您将100%确定您通过OUTPUT子句获得了正确的广告系列ID,并且实际上并不需要锁定交易。据我所知,SQL Server不允许您在OUTPUT子句中引用连接表中的列(与DELETE ... OUTPUTUPDATE ... OUTPUT不同),因此广告系列ID 必须成为INSERT的{​​{1}}子句的一部分。

由于广告系列ID不是输出的一部分,因此该解决方案几乎是HLGEM答案的复杂版本,但它可能对您有用。

答案 3 :(得分:0)

您应该将更新的地址id存储到使用INSERT的OUTPUT子句填充的表变量中:

create table TBL_ADDRESSBOOKADDRESSES (
    adds_ABMID int identity(1,1) not null,
    col_1 varchar(100),
    col_2 varchar(100));
go

create table TBL_RECIPIENTS (
    adds_ABMID int not null,    
    col_1 varchar(100),
    col_2 varchar(100));
go

create table TBL_CAMPAIGNS (
    campaign_AddressBook int,
    campaign_Status int);
go

insert into TBL_ADDRESSBOOKADDRESSES (col_1, col_2)
    values ('spam', 'is evil');
insert into TBL_ADDRESSBOOKADDRESSES (col_1, col_2)
    values ('all mass mail', 'is spam');


insert into TBL_CAMPAIGNS (campaign_AddressBook, campaign_Status)
    values (1,1);
insert into TBL_CAMPAIGNS (campaign_AddressBook, campaign_Status)
    values (2,1);
go  

set nocount on;
declare @newRecipients table (adds_ABMID int);
begin transaction
insert into TBL_RECIPIENTS (adds_ABMID, col_1, col_2)
    output inserted.adds_ABMID into @newRecipients
    SELECT a.adds_ABMID
        , a.col_1
        , a.col_2
    FROM TBL_ADDRESSBOOKADDRESSES a 
    INNER JOIN TBL_CAMPAIGNS ON a.adds_ABMId = TBL_CAMPAIGNS.campaign_AddressBook
    WHERE TBL_CAMPAIGNS.campaign_Status = 1
update TBL_CAMPAIGNS 
    set campaign_Status = 2
    from TBL_CAMPAIGNS as c
    join @newRecipients as new on c.campaign_AddressBook = new.adds_ABMID;
commit; 
go

select * from TBL_RECIPIENTS;
select * from TBL_CAMPAIGNS;
go