Reputation: 1596
I have a table with a complex primary key. Also I have a Service Broker service which receives XML message which basically looks like the following:
<TableName>
<CHANGED key1="1" key2="2" key3="3" timestamp="00:00:01"/>
<CHANGED key1="1" key2="2" key3="3" timestamp="00:00:02"/>
<CHANGED key1="1" key2="2" key3="3" timestamp="00:00:03"/>
</TableName>
My goal is to insert those values into a table.
I tried the following query:
INSERT INTO TableName (KEY1, KEY2, KEY3, TS)
SELECT
Tbl.Col.value('@*[1]', 'int'),
Tbl.Col.value('@*[2]', 'int'),
Tbl.Col.value('@*[3]', 'int'),
Tbl.Col.value('@*[4]', 'datetime')
FROM @MESSAGE.nodes('//CHANGED') Tbl(Col)
But in case when we have several records with the same complex key (key1, key2, key3) and different timestamp (value I need for my biz logic) this query fails with the following error message:
Violation of PRIMARY KEY constraint 'TableName'. Cannot insert duplicate key in object 'dbo.TableName'. The duplicate key value is (1, 2, 3).
Is there a way to insert only distinct values with the latest timestamp from that message?
Upvotes: 1
Views: 751
Reputation: 138990
Do a group by
on the keys and aggregate on timestamp
(min or max?).
INSERT INTO TableName (KEY1, KEY2, KEY3, TS)
SELECT key1, key2, key3, MIN(ts)
FROM
(
SELECT
Tbl.Col.value('@key1', 'int') AS key1,
Tbl.Col.value('@key2', 'int') AS key2,
Tbl.Col.value('@key3', 'int') AS key3,
Tbl.Col.value('@timestamp', 'datetime') as ts
FROM @MESSAGE.nodes('//CHANGED') Tbl(Col)
) AS M
GROUP BY key1, key2, key3
To be really safe you should use the attribute names instead of position()
. According to Limitations of the xml Data Type the order of attributes is not guaranteed.
The order of attributes in an XML instance is not preserved. When you query the XML instance stored in the xml type column, the order of attributes in the resulting XML may be different from the original XML instance.
Upvotes: 2