CREATE FUNCTION dbo.GetRow(@XMLDT AS xml)
RETURNS nvarchar(10)
WITH SCHEMABINDING
AS
BEGIN
RETURN @XMLDT.value('(./row/text())[1]','nvarchar(10)');
END;
ALTER TABLE dbo.IQ
ADD RowValue AS dbo.GetRow(XMLDT);
And a constraint to enforce the desired uniqueness:
ALTER TABLE dbo.IQ
ADD CONSTRAINT UQ__IQ_XMLDT_RowValue
UNIQUE (RowValue);
Demo:
-- Succeeds
INSERT INTO IQ (XMLDT)
VALUES('<row>sdsdf</row>');
-- Msg 2627, Level 14, State 1, Line 1
-- Violation of UNIQUE KEY constraint 'UQ__IQ_XMLDT_RowValue'
INSERT INTO IQ (XMLDT)
VALUES('<row>sdsdf</row>');
Can you stage it twice? First, shred the data into rows of XML, and then read the columns from the rows. Something like:
with XmlNamespaces ( 'urn:xpaykj-report-xml-1.0' as xkj)
Select
xItem.query('.') as RowXML
Into #loadtemp
From @xmldoc.nodes('xkj:output-data/xkj:childs/xkj:child[@name="output"]/xkj:childs/xkj:child[@name="lvla"]/xkj:childs/xkj:child[@name="lvlb"]/xkj:childs/xkj:child[@name="lvlc"]/xkj:properties') as x(xItem)
should give you rows of XML; then apply your value statements to shred the table into columns.
I suspect you are using an AFTER INSERT trigger (if you don't specify something else triggers are the AFTER type, give the full code for your trigger definition for us to be sure) so this is expected: your trigger fires after the insert so it will always see the row you have just put in.
Instead of IF EXISTS ... you could instead do IF (SELECT COUNT(*) ...) > 1 which will check to see if your new row(s) bring the total to more than one.
You could also use an INSTEAD OF INSERT trigger which might be a little more efficient (doing less work that you later rollback) though I doubt the difference will be significant unless you have a very insert-heavy workload on that table with lots of duplicates.
Two side points:
Firstly make sure you deal with UPDATES as well or you could get duplicates in that way too.
Secondly, make sure what you are doing is actually worthwhile: trying to enforce data integrity on free-text entry fields like "description" is generally a lost cause. You could have two entries that are identical apart from one having a double space or spelling error, and your check won't pick them out as equivalent.
Best Answer
Given this table:
We first need a scalar function to extract the value of interest from the XML:
Now we can add a computed column that uses the function:
And a constraint to enforce the desired uniqueness:
Demo: