복붙노트

[SQL] SQL 서버에서 XML 문서의 노드 순서를 찾기

SQL

SQL 서버에서 XML 문서의 노드 순서를 찾기

어떻게 XML 문서의 노드의 순서를 찾을 수 있습니까?

내가 가지고있는 것은이 같은 문서입니다 :

<value code="1">
    <value code="11">
        <value code="111"/>
    </value>
    <value code="12">
        <value code="121">
            <value code="1211"/>
            <value code="1212"/>
        </value>
    </value>
</value>

나는 다음과 같이 정의 테이블에이 일을 얻으려고

CREATE TABLE values(
    code int,
    parent_code int,
    ord int
)

XML 문서의 값의 순서를 보존 (그들은 자신의 코드에 의해 주문 될 수 없다). 내가 말할 수 있어야합니다

SELECT code 
FROM values 
WHERE parent_code = 121 
ORDER BY ord

그 결과, 결정 론적이어야한다

code
1211
1212

나는 시도

SELECT 
    value.value('@code', 'varchar(20)') code, 
    value.value('../@code', 'varchar(20)') parent, 
    value.value('position()', 'int')
FROM @xml.nodes('/root//value') n(value)
ORDER BY code desc

그러나 위치 () 함수 ( '위치 ()'만 술어 또는 XPath를 선택 내에서 사용 할 수있다)을 허용하지 않습니다.

나는 그것이 어떤 방식으로 가능한 것 같아요,하지만 어떻게?

해결법

  1. ==============================

    1.각 노드를 이전 형제 노드의 수를 계산하여 위치 () 함수를 에뮬레이션 할 수 있습니다 :

    각 노드를 이전 형제 노드의 수를 계산하여 위치 () 함수를 에뮬레이션 할 수 있습니다 :

    SELECT
        code = value.value('@code', 'int'),
        parent_code = value.value('../@code', 'int'),
        ord = value.value('for $i in . return count(../*[. << $i]) + 1', 'int')
    FROM @Xml.nodes('//value') AS T(value)
    

    결과 집합은 다음과 같습니다

    code   parent_code  ord
    ----   -----------  ---
    1      NULL         1
    11     1            1
    111    11           1
    12     1            2
    121    12           1
    1211   121          1
    1212   121          2
    

    그것이 작동하는 방법 :

  2. ==============================

    2.SQL 서버 ROW_NUMBER ()는 사실에 의해 주문하는 XML 노드 열을 받아들입니다. 당신이 할 수있는 재귀 CTE와 결합 :

    SQL 서버 ROW_NUMBER ()는 사실에 의해 주문하는 XML 노드 열을 받아들입니다. 당신이 할 수있는 재귀 CTE와 결합 :

    declare @Xml xml = 
    '<value code="1">
        <value code="11">
            <value code="111"/>
        </value>
        <value code="12">
            <value code="121">
                <value code="1211"/>
                <value code="1212"/>
            </value>
        </value>
    </value>'
    
    ;with recur as (
        select
            ordr        = row_number() over(order by x.ml),
            parent_code = cast('' as varchar(255)),
            code        = x.ml.value('@code', 'varchar(255)'),
            children    = x.ml.query('./value')
        from @Xml.nodes('value') x(ml)
        union all
        select
            ordr        = row_number() over(order by x.ml),
            parent_code = recur.code,
            code        = x.ml.value('@code', 'varchar(255)'),
            children    = x.ml.query('./value')
        from recur
        cross apply recur.children.nodes('value') x(ml)
    )
    select *
    from recur
    where parent_code = '121'
    order by ordr
    

    여담으로, 당신은이 작업을 수행 할 수 있으며, 그것은 당신이 무엇을 기대 할 수 있습니다 :

    select x.ml.query('.')
    from @Xml.nodes('value/value')x(ml)
    order by row_number() over (order by x.ml)
    

    이 작품을 경우, 당신은 단지 ROW_NUMBER 않고 직접 x.ml으로 주문할 수없는 이유 ()를 통해 내 능력 밖입니다.

  3. ==============================

    3.당신은 너무 같은 x.nodes (에 의해 반환 된 XML) 함수의 위치를 ​​얻을 수 있습니다 :

    당신은 너무 같은 x.nodes (에 의해 반환 된 XML) 함수의 위치를 ​​얻을 수 있습니다 :

    row_number() over (order by (select 0))
    

    예를 들면 :

    DECLARE @x XML
    SET @x = '<a><b><c>abc1</c><c>def1</c></b><b><c>abc2</c><c>def2</c></b></a>'
    
    SELECT
        b.query('.'),
        row_number() over (partition by 0 order by (select 0))
    FROM
        @x.nodes('/a/b') x(b)
    
  4. ==============================

    4.erikkallen에 의한 대답은 절대적으로 올바른 것입니다.

    erikkallen에 의한 대답은 절대적으로 올바른 것입니다.

    원본 문서 / 스키마가 변경 될 수있는 경우에는, 대안 특성에 위치 / 인덱스를 저장하는 것이다. 나는 XML의 "발신자"이고 필요 그것을 바탕으로 수행 할 것을 쿼리의 유형 누가 따라 두 가지 방식의 혼합을 사용합니다. 하루의 끝에서 나는 SQL Server의 가능성 "바보 저장"을 제외하고 XML 대부분의 사용을 후회하고 내가 정상화 테이블을 위해 (XML)를 덤프 할 수있을 때 일반적으로 기쁘게 생각합니다.

    "엔터프라이즈 급"제품의 언급되지 않은 한계 행복 거래 - 경이로움은 끝이 없을.

  5. ==============================

    5.이 문서 그것이 불가능하다이 연결 항목 만 연결 항목에 따라 두 가지 해결 방법이 포함되어 있습니다.

    이 문서 그것이 불가능하다이 연결 항목 만 연결 항목에 따라 두 가지 해결 방법이 포함되어 있습니다.

    나는 이런 식으로 작업을 수행합니다

    WITH n(i) AS (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9),
         o(i) AS (SELECT n3.i * 100 + n2.i * 10 + n1.i FROM n n1, n n2, n n3)
    SELECT v.value('@code', 'varchar(20)') AS code,
           v.value('../@code', 'varchar(20)') AS parent,
           o.i AS ord
      FROM o
     CROSS APPLY @xml.nodes('/root//value[sql:column("o.i")]') x(v)
     ORDER BY o.i
    
  6. ==============================

    6.내가 @ 벤과로 답을 ... 새로운 솔루션을 얻을

    내가 @ 벤과로 답을 ... 새로운 솔루션을 얻을

     row_number() over (order by (select null))
    

    같이

      SELECT value.value('@code', 'varchar(20)') code, 
      value.value('../@code', 'varchar(20)') parent, 
      row_number() over (order by (select null))
      FROM @xml.nodes('/root//value') n(value)
    
  7. from https://stackoverflow.com/questions/1134075/finding-node-order-in-xml-document-in-sql-server by cc-by-sa and MIT license