2015-04-16 3 views
1

Мне нужна помощь с моим запросом ... Я не хочу, чтобы получить идентификаторы trade, которые являются дубликатами и отсутствуют LegId. Не могли бы вы мне помочь?Извлеките дубликаты из XML

Мой XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<data> 
<value> 
    <TradeId>928</TradeId> 
    <LegId>1</LegId> 
</value> 
<value> 
    <TradeId>928</TradeId> 
    <LegId>2</LegId> 
</value> 
<value> 
    <TradeId>928</TradeId> 
    //MISSING LEGID HERE 
</value> 
<value> 
    <TradeId>929</TradeId> 
    <LegId>1</LegId> 
</value> 
<value> 
    <TradeId>929</TradeId> 
    <LegId>2</LegId> 
</value> 
<value> 
    <TradeId>930</TradeId> 
    <LegId>2</LegId> 
</value> 
</data> 

Im объявляя этот XML в переменную, а затем заполнение #temptable с результатом:

SELECT * 
INTO #tradeIdDuplicatesToIgnore 
FROM 
(
    SELECT 
     e.value('TradeId[1]','varchar(50)') AS strTradeId 
     ,e.value('LegId[1]','int') AS LegId 
    FROM @xmlData.nodes('data/value') AS elements(e) 
    WHERE 1 = 1 
) AS t 



SELECT * 
FROM #tradeIdDuplicatesToIgnore AS t 

Это дает мне следующий вывод: output

Единственная строка, в которой я не была в этом случае, - это номер 3, тот, который отмечен желтым цветом (мне нужен только столбец TradeId). Этот запрос:

SELECT t.strTradeId 
INTO #tradeIdDuplicatesToIgnore 
FROM 
(
    SELECT 
     e.value('TradeId[1]','varchar(50)') AS strTradeId 
     ,e.value('LegId[1]','int') AS LegId 
    FROM @xmlData.nodes('data/value') AS elements(e) 
) AS t 
WHERE 1 = 1 
--AND  t.LegId IS NULL 
GROUP BY t.strTradeId 
HAVING COUNT(t.strTradeId) > 1 


SELECT * 
FROM #tradeIdDuplicatesToIgnore AS t 

И это оставляет меня с двумя рядами с 928 и 929, но я не могу получить один были LegId IS NULL ...

Запрошенный выход из этого случая: один с TradeId 928.

Не могли бы вы помочь мне в этом?

+0

вы пытались 'DISTINCT'? – DLeh

ответ

3

Один из возможных способов, изменить XPath для предложения FROM выбрать только <value> S не имеющие ребенка <LegId>:

data/value[not(LegId)] 

ВИДЕТЬ XPath в действии:

SELECT * 
INTO #tradeIdDuplicatesToIgnore 
FROM 
(
    SELECT 
     e.value('TradeId[1]','varchar(50)') AS strTradeId 
     ,e.value('LegId[1]','int') AS LegId 
    FROM @xmlData.nodes('data/value[not(LegId)]') AS elements(e) 
    WHERE 1 = 1 
) AS t 

SELECT * 
FROM #tradeIdDuplicatesToIgnore AS t 

Выход:

enter image description here

Обновление:

Я пропустил требование проверить наличие дубликатов раньше. Так вот другой способ добиться того же, но с добавлением дубликатов проверки:

SELECT * 
INTO #tradeIdDuplicatesToIgnore 
FROM 
(
    SELECT 
     e.value('TradeId[1]','varchar(50)') AS strTradeId 
     ,e.value('LegId[1]','int') AS LegId 
    FROM @xmlData.nodes('data/value') AS elements(e) 
    WHERE 1 = 1 
) AS t 

SELECT t.strTradeId 
FROM #tradeIdDuplicatesToIgnore AS t 
     INNER JOIN 
     (
      SELECT COUNT(*) 'count', strTradeId 
      FROM #tradeIdDuplicatesToIgnore 
      GROUP BY strTradeId 
     ) As t2 on t2.strTradeId = t.strTradeId 
WHERE LegId IS NULL AND t2.count > 1 

Выход:

enter image description here

Update 2:

;with T as (
    SELECT 
     e.value('TradeId[1]','varchar(50)') AS strTradeId 
     ,e.value('LegId[1]','int') AS LegId 
    FROM @xmlData.nodes('data/value') AS elements(e) 
) 
SELECT * 
INTO #tradeIdDuplicatesToIgnore 
FROM 
(
    SELECT T.strTradeId 
    FROM T 
    GROUP BY T.strTradeId 
    HAVING COUNT(*)>1 AND COUNT(*)>COUNT(T.LegId) 
) AS t 

SELECT * FROM #tradeIdDuplicatesToIgnore 
+0

Большое спасибо. Можно ли переместить дубликат проверки на вставку #tradeIdDuplicatesToIgnore? – MrProgram

+0

@krillezzz, насколько я вижу, невозможно использовать тот же подход. подсчет всех записей (с 'GROUP BY'), а фильтрация для нулевых записей за один раз - непростая задача, к счастью, Роман Пекар придумал умный подход (+1 для него):' count (*)> count (c .LegId) '. Проверьте ** обновить 2 **. – har07

+0

извините, но я не думаю, что копирование кода из моего ответа справедливо. версия cte полностью копируется из моего ответа. –

4

вы можете используйте этот запрос, чтобы получить дубликаты с нулями:

;with cte_splitted as (
    select 
     e.e.value('TradeId[1]','varchar(50)') as strTradeId, 
     e.e.value('LegId[1]','int') as LegId 
    from @xmlData.nodes('data/value') as e(e) 
) 
select 
    c.strTradeId 
into #tradeIdDuplicatesToIgnore 
from cte_splitted as c 
group by 
    c.strTradeId 
having 
    count(*) > count(c.LegId) and -- count of all records <> count of not null records 
    count(*) > 1 -- there're more than 1 record 

sql fiddle demo

Смежные вопросы