سؤال

بالنظر إلى العينة التالية من XML و select العبارة التي تمزيق ملف XML إلى علاقة، ماذا أحتاج هو العمود الثاني من select ليكون الترتيبي للفئة (أي 1 للاتجاهات و2 للألوان في هذه الحالة).

ملحوظة:يتم ترك القيمة الحرفية "rank()" في التحديد كعنصر نائب.كنت أتجول باستخدام rank, ، ولكن دون نجاح.

declare @x xml
set @x = '
    <root>
        <category>
            <item value="north"/>
            <item value="south"/>
            <item value="east"/>
            <item value="west"/>
        </category>
        <category>
            <item value="red"/>
            <item value="green"/>
            <item value="blue"/>
        </category>
    </root>'

select c.value('./@value', 'varchar(10)') as "ItemValue", 
       'rank()' as "CategoryNumber"
from @x.nodes('//item') as t(c)
هل كانت مفيدة؟

المحلول

لدى جاكوب سيباستيان أيضًا حل مثير للاهتمام تم تقديمه في منشور مدونته:

XQuery Lab 23 - استرجاع القيم وموضع العناصر

مع اقتراح جاكوب، يمكنني إعادة كتابة الاستعلام الخاص بك ليكون:

SELECT
    x.value('@value','VARCHAR(10)') AS 'ItemValue',        
    p.number as 'CategoryNumber'
FROM
    master..spt_values p
CROSS APPLY 
    @x.nodes('/root/category[position()=sql:column("number")]/item') n(x) 
WHERE
    p.type = 'p'

وأحصل على الإخراج المطلوب:

ItemValue   CategoryNumber
---------   --------------
north           1
south           1
east            1
west            1
red             2
green           2
blue            2

لسوء الحظ، لا يوجد أي من الحلول الأكثر وضوحًا مثل position() أو fn:id() يبدو أن الوظائف أ) تعمل في SQL Server أو ب) تكون مدعومة في SQL Server على الإطلاق :-(

أتمنى أن يساعدك هذا

مارك

نصائح أخرى

ربما مثل هذا:تحصل على العنصر الأول من كل فئة وتستخدمه كمعرف.

هذا:

select c.value('./@value', 'varchar(10)') as "ItemValue", 
    c.value('../item[1]/@value', 'varchar(10)') as "CategoryNumber"
from @x.nodes('//item') as t(c)

عائدات:

Item Value | CategoryNumber
---------------------------
north      | north
south      | north
east       | north
west       | north
red        | red
green      | red
blue       | red

وبعد ذلك فقط

select c.value('./@value', 'varchar(10)') as "ItemValue", 
   RANK() OVER (ORDER BY c.value('../item[1]/@value', 'varchar(10)')) as "CategoryNumber"
from @x.nodes('//item') as t(c)

ومع ذلك يعود:

Item Value | CategoryNumber
---------------------------
north      | 1
south      | 1
east       | 1
west       | 1
red        | 5
green      | 5
blue       | 5

لكنها لا تزال خطوة إلى الأمام.

لا يمكنك استخدام position() لإنتاج المخرجات (لماذا؟؟)، ولكن يمكنك استخدامه كمرشحات XPath:

 with numbers (n) as (
  select 1
  union all select 2
  union all select 3
  union all select 4
  union all select 5)
 select i.x.value('@value', 'varchar(10)') as [ItemValue],
    n.n as [rank]
  from numbers n
  cross apply @x.nodes('/root/category[position()=sql:column("n.n")]') as c(x)
  cross apply c.x.nodes('item') as i(x);

يمكنك استخدام جدول الأعداد الحقيقية للرتب الأعلى.لن يكون الأمر فعالًا بالنسبة لعدد كبير جدًا من الفئات في مستند واحد، ولكن بالنسبة للأعداد المعتدلة (العشرات والمئات) ستعمل بشكل جيد.

على غرار إجابة Lukasz، تمكنت من تحقيق النتيجة المرجوة من خلال:

SELECT
  I.Item_Instance.value('@value','VARCHAR(10)') AS Item_Value,
  DENSE_RANK() OVER (ORDER BY C.Category_Instance) AS Category_Ordinal  
FROM @x.nodes('/root') AS R(Root_Instance)
CROSS APPLY R.Root_Instance.nodes('category') AS C(Category_Instance)
CROSS APPLY C.Category_Instance.nodes('item') AS I(Item_Instance);

يعود:

Item_Value Category_Ordinal
---------- --------------------
north      1
south      1
east       1
west       1
red        2
green      2
blue       2
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top