2016-04-21 48 views
2

这是XML我:T-SQL MERGE语句更新时,条件匹配的新插入的记录

<?xml version="1.0" encoding="UTF-8"?> 
<Data> 
    <Record> 
     <ServerId>1</ServerId> 
     <CompanyId>1</CompanyId> 
     <InstanceId>2</InstanceId> 
     <TemplateId>23</TemplateId> 
     <ContactId>11052</ContactId> 
     <RecordId>11462</RecordId> 
     <TaskId>677</TaskId> 
     <EntryDate>2016-04-21 14:17:02:813</EntryDate> 
     <EntryKey>key_test_1</EntryKey> 
     <EntryValue>value_test_1</EntryValue> 
    </Record> 
    <Record> 
     <ServerId>1</ServerId> 
     <CompanyId>1</CompanyId> 
     <InstanceId>2</InstanceId> 
     <TemplateId>23</TemplateId> 
     <ContactId>11052</ContactId> 
     <RecordId>11462</RecordId> 
     <TaskId>677</TaskId> 
     <EntryDate>2016-04-21 14:17:02:873</EntryDate> 
     <EntryKey>key_test_2</EntryKey> 
     <EntryValue>value_test_2</EntryValue> 
    </Record> 
    <Record> 
     <ServerId>1</ServerId> 
     <CompanyId>1</CompanyId> 
     <InstanceId>2</InstanceId> 
     <TemplateId>23</TemplateId> 
     <ContactId>11052</ContactId> 
     <RecordId>11462</RecordId> 
     <TaskId>677</TaskId> 
     <EntryDate>2016-04-21 14:17:02:935</EntryDate> 
     <EntryKey>key_test_1</EntryKey> 
     <EntryValue>value_test_3</EntryValue> 
    </Record> 
</Data> 

,这是插入或MERGE语句更新此数据为单个表:

merge WRF_REPOSITORY_CUSTOM_DATA rep 
using (select 
     entity.value('ServerId[1]', 'int') as ServerId, 
     entity.value('CompanyId[1]', 'int') as CompanyId, 
     entity.value('InstanceId[1]', 'int') as InstanceId, 
     entity.value('TemplateId[1]', 'int') as TemplateId, 
     entity.value('ContactId[1]', 'bigint') as ContactId, 
     entity.value('RecordId[1]', 'bigint') as RecordId, 
     entity.value('TaskId[1]', 'bigint') as TaskId, 
     entity.value('EntryDate[1]', 'datetime') as EntryDate, 
     entity.value('EntryKey[1]', 'varchar(max)') as EntryKey, 
     entity.value('EntryValue[1]', 'varchar(max)') as EntryValue 
     from @xmlInsertOrReplace.nodes('/Data/Record') as T(entity)) as dat 
on 
    rep.ServerId = dat.ServerId and 
    rep.CompanyId = dat.CompanyId and 
    rep.InstanceId = dat.InstanceId and 
    rep.TemplateId = dat.TemplateId and 
    rep.ContactId = dat.ContactId and 
    rep.RecordId = dat.RecordId and 
    rep.EntryKey = dat.EntryKey 
when MATCHED then update set 
    rep.TaskId = dat.TaskId, 
    rep.EntryDate = dat.EntryDate, 
    rep.EntryValue = dat.EntryValue 
when NOT MATCHED then 
    insert (ServerId, CompanyId, InstanceId, TemplateId, ContactId, RecordId, TaskId, EntryDate, EntryKey, EntryValue) 
    values (dat.ServerId, dat.CompanyId, dat.InstanceId, dat.TemplateId, dat.ContactId, dat.RecordId, dat.TaskId, dat.EntryDate, dat.EntryKey, dat.EntryValue); 

当表中没有记录时,我期望的是第一个xml记录将被插入,第二个xml记录将被插入,第三个xml记录将更新第一个表记录,因为它与条件匹配。实际发生的是我得到3插入,而不是2插入和1更新。

结果截图:enter image description here

有没有办法迫使MERGE语句做COMMIT或东西每次插入或更新后?我不想将xml记录分组或选择最大/最后一个。

UPDATE:

我用类似于第一个多一个合并的行动。唯一的区别是这个连接值。

when MATCHED then update set 
    rep.TaskId = dat.TaskId, 
    rep.EntryDate = dat.EntryDate, 
    rep.EntryValue = case len(isnull(rep.EntryValue, '')) when 0 then dat.EntryValue else rep.EntryValue + ';' + dat.EntryValue end 

和预期的结果应该是:

key_test_1 | value_test_1;value_test_3 
key_test_2 | value_test_2 
+4

号MERGE是一个单一的陈述。如果你想先插入然后更新,你需要使用两个单独的语句。 –

+0

@肖恩兰格是正确的。 MERGE语句将现有表中的数据与解析的XML数据中的数据进行比较。 – Steven

+3

*“我不想分组xml记录或选择最大/最后一个。”* - 为什么不?这似乎是解决方案,为什么要插入第一个记录,如果所有的字段都会被写入第三条记录,那么为什么呢? – GarethD

回答

2

你可以试试这个:

使用ROW_NUMBER找到最当前记录在您的XML和忽略前辈之一,这将无论如何都会被覆盖...

WITH shreddedXML AS 
(
    select 
     entity.value('ServerId[1]', 'int') as ServerId, 
     entity.value('CompanyId[1]', 'int') as CompanyId, 
     entity.value('InstanceId[1]', 'int') as InstanceId, 
     entity.value('TemplateId[1]', 'int') as TemplateId, 
     entity.value('ContactId[1]', 'bigint') as ContactId, 
     entity.value('RecordId[1]', 'bigint') as RecordId, 
     entity.value('TaskId[1]', 'bigint') as TaskId, 
     entity.value('EntryDate[1]', 'datetime') as EntryDate, 
     entity.value('EntryKey[1]', 'varchar(max)') as EntryKey, 
     entity.value('EntryValue[1]', 'varchar(max)') as EntryValue 
    from @xmlInsertOrReplace.nodes('/Data/Record') as T(entity) 
) 
,SearchForMostActualRows AS 
(
    SELECT ROW_NUMBER() OVER(PARTITION BY ServerId,CompanyId,InstanceId,TemplateId,ContactId,RecordId,EntryKey ORDER BY EntryDate DESC) AS Nr 
      ,* 
    FROM shreddedXML 
) 
SELECT * 
FROM SearchForMostActualRows 
WHERE Nr=1 

现在请做您的MERGE与此...

+0

问题是我不能忽视任何记录。我会用原因更新我的问题。 – HABJAN

+0

@HABJAN我刚刚读了原因。只需将我的查询更改为'SELECT * INTO#tempTable'。在接下来的步骤中,您使用'SELECT * FROM #tempTable WHERE Nr = 1'来执行'MERGE',然后在'SELECT * FROM #tempTable WHERE Nr> 1'处做任何事情' – Shnugo

+0

即使这样也解决不了我问题,它指出我正确的方向。谢谢。 – HABJAN