简体   繁体   English

SQL Server - 使用触发器在插入期间设置列值

[英]SQL Server--Setting column value during insert using trigger

I have a table with the following columns: 我有一个包含以下列的表:

id, xml, receivedDate, processed, processedDateTime, orderNumber id,xml,receivedDate,processed,processedDateTime,orderNumber

id, receivedDate, and processed all have default values. id,receivedDate和processed都具有默认值。

The XML being stored in the xml column looks like this: 存储在xml列中的XML如下所示:

<v1:OrderStatus xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.dell.com/Services/DMT/OrderStatus/V1">
  <v1:BusinessUnitId>11</v1:BusinessUnitId>
  <v1:OrderNumber>964806604</v1:OrderNumber>
  <v1:OrderStatusCode>RDD</v1:OrderStatusCode>
  <v1:StatusDateTime>2016-04-12T01:16:28</v1:StatusDateTime>
  <v1:RDD_Date>2016-04-19T00:00:00</v1:RDD_Date>
</v1:OrderStatus>

When the XML is inserted to the table, I need to grab the value for OrderNumber and set it in the orderNumber column. 当XML插入到表中时,我需要获取OrderNumber的值并将其设置在orderNumber列中。 I developed a trigger to try to accomplish this, but instead of setting the the value in only the newly inserted row, it sets the value for ALL the rows in the table. 我开发了一个触发器来尝试完成此操作,但它不是仅在新插入的行中设置值,而是设置表中所有行的值。

My trigger looks like: 我的触发器看起来像:

  declare @ordernumber varchar(50)  
  select @ordernumber=(select xml.value('(//*:OrderNumber)[1]', 'varchar(max)') as orderNumber from inserted)

    Update [dbo].[dell.des.OCIMessages] 
    set orderNumber=@ordernumber
      END

I have another trigger on a different table which joins on the orderNumber value between these two tables and I use this other trigger after an insert/update to find the row with the matching orderNumber and processed=0 and then set processed=1 and also set the processedDateTime field. 我在另一个表上有另一个触发器,它连接在这两个表之间的orderNumber值,我在插入/更新后使用另一个触发器来查找匹配orderNumber并处理= 0的行,然后设置processed = 1并设置processedDateTime字段。

Unfortunately, since my first trigger is updating all the rows to use the same order number value, my second trigger inadvertently always updates all the rows because the ordernumber values are the same for every row in my table. 不幸的是,由于我的第一个触发器是更新所有行以使用相同的订单号值,我的第二个触发器无意中总是更新所有行,因为我的表中的每一行的ordernumber值都相同。

Can someone please shed some light on what is wrong with my trigger so that it only updates just the inserted row? 有人可以说明我的触发器有什么问题,以便它只更新插入的行吗?

BTW, I'm only ever inserting a single row at a time, so I don't have to worry about my trigger have to deal with multiple records. 顺便说一句,我一次只插入一行,所以我不必担心我的触发器必须处理多个记录。

Thanks! 谢谢!

You could use a where condition on your update: 您可以在更新中使用where条件:

declare @ordernumber varchar(50), @id int 
select @ordernumber= xml.value('(//*:OrderNumber)[1]', 'varchar(max)') as orderNumber, @id = id from inserted

Update [dbo].[dell.des.OCIMessages] 
set orderNumber=@ordernumber 
where id = @id
  END

Or you could just use the set-based option: 或者您可以使用基于集合的选项:

Update oci Set oci.orderNumber = inserted.xml.value('(//*:OrderNumber)[1]', 'varchar(max)')
from [dbo].[dell.des.OCIMessages] oci join inserted on oci.id = inserted.id

What about this? 那这个呢?

You need a unser defined function to retrieve your value 您需要一个未定义的函数来检索您的值

CREATE FUNCTION dbo.GetOrderNumber(@xml xml)
RETURNS VARCHAR(MAX)
AS
BEGIN
    RETURN @xml.value('(//*:OrderNumber)[1]', 'varchar(max)');
END

Define your table with a computed column 使用计算列定义表

CREATE TABLE dbo.Test(id INT, xml XML, OrderNumber AS dbo.GetOrderNumber(xml));

And this is how it works 这就是它的工作原理

declare @xml1 xml=
'<v1:OrderStatus xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.dell.com/Services/DMT/OrderStatus/V1">
  <v1:OrderNumber>11111</v1:OrderNumber>
</v1:OrderStatus>';

declare @xml2 xml=
'<v1:OrderStatus xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.dell.com/Services/DMT/OrderStatus/V1">
  <v1:OrderNumber>22222</v1:OrderNumber>
</v1:OrderStatus>';

declare @xml3 xml=
'<v1:OrderStatus xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.dell.com/Services/DMT/OrderStatus/V1">
  <v1:OrderNumber>33333</v1:OrderNumber>
</v1:OrderStatus>';    

insert into dbo.Test VALUES(1,@xml1),(2,@xml2);

select * from dbo.Test;

insert into dbo.Test select 3,@xml3;

select * from dbo.Test;

I place a second answer, because this is a completely differing approach: 我给出了第二个答案,因为这是一个完全不同的方法:

Create a normal table 创建一个普通表

CREATE TABLE dbo.Test(id INT, xml XML, OrderNumber VARCHAR(100));

Create an "INSTEAD OF" Trigger 创建一个“INSTEAD OF”触发器

CREATE TRIGGER dbo.InsertToTest ON  dbo.Test
   INSTEAD OF INSERT
AS 
BEGIN
    INSERT INTO dbo.Test(id,xml,OrderNumber)
    SELECT id,xml,xml.value('(//*:OrderNumber)[1]', 'varchar(max)') 
    FROM inserted
END
GO

And this is how it works 这就是它的工作原理

declare @xml1 xml=
'<v1:OrderStatus xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.dell.com/Services/DMT/OrderStatus/V1">
  <v1:OrderNumber>11111</v1:OrderNumber>
</v1:OrderStatus>';

declare @xml2 xml=
'<v1:OrderStatus xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.dell.com/Services/DMT/OrderStatus/V1">
  <v1:OrderNumber>22222</v1:OrderNumber>
</v1:OrderStatus>';

declare @xml3 xml=
'<v1:OrderStatus xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.dell.com/Services/DMT/OrderStatus/V1">
  <v1:OrderNumber>33333</v1:OrderNumber>
</v1:OrderStatus>';    

insert into dbo.Test VALUES(1,@xml1,'SomeValue'),(2,@xml2,'AnotherValue');

select * from dbo.Test;

insert into dbo.Test select 3,@xml3,null;

select * from dbo.Test;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM