Aracılığıyla paylaş


FLWOR deyimi ve yinelemesi (XQuery)

Şunlar için geçerlidir: SQL Server

XQuery, FLWOR yineleme söz dizimini tanımlar. FLWOR , , for, letwhereve order bykısaltmasıdırreturn.

FLWOR deyimi aşağıdaki bölümlerden oluşur:

  • Giriş dizilerine bir veya daha fazla yineleyici değişkeni bağlayan bir veya daha fazla FOR yan tümce.

    Giriş dizileri, XPath ifadeleri gibi diğer XQuery ifadeleri olabilir. Bunlar düğüm dizileri veya atomik değer dizileridir. Atomik değer dizileri değişmez değerler veya oluşturucu işlevleri kullanılarak oluşturulabilir. SQL Server'da giriş dizileri olarak yapılı XML düğümlerine izin verilmez.

  • İsteğe bağlı let bir yan tümce. Bu yan tümce belirli bir yineleme için verilen değişkene bir değer atar. Atanan ifade, XPath ifadesi gibi bir XQuery ifadesi olabilir ve bir düğüm dizisi veya atomik değerler dizisi döndürebilir. Atomik değer dizileri değişmez değerler veya oluşturucu işlevleri kullanılarak oluşturulabilir. SQL Server'da giriş dizileri olarak yapılı XML düğümlerine izin verilmez.

  • Yineleyici değişkeni. Bu değişken, anahtar sözcüğünü kullanarak isteğe bağlı bir tür onayına as sahip olabilir.

  • İsteğe bağlı where bir yan tümce. Bu yan tümce yinelemeye bir filtre koşulu uygular.

  • İsteğe bağlı order by bir yan tümce.

  • bir return ifade. yan tümcesindeki return ifade FLWOR deyiminin sonucunu oluşturur.

Örneğin, aşağıdaki sorgu ilk üretim konumundaki <Step> öğeler üzerinde yinelenir ve düğümlerin <Step> dize değerini döndürür:

DECLARE @x AS XML;

SET @x = '<ManuInstructions ProductModelID="1" ProductModelName="SomeBike" >
<Location LocationID="L1" >
  <Step>Manu step 1 at Loc 1</Step>
  <Step>Manu step 2 at Loc 1</Step>
  <Step>Manu step 3 at Loc 1</Step>
</Location>
<Location LocationID="L2" >
  <Step>Manu step 1 at Loc 2</Step>
  <Step>Manu step 2 at Loc 2</Step>
  <Step>Manu step 3 at Loc 2</Step>
</Location>
</ManuInstructions>';

SELECT @x.query('
   for $step in /ManuInstructions/Location[1]/Step
   return string($step)
');

Sonuç şu şekildedir:

Manu step 1 at Loc 1 Manu step 2 at Loc 1 Manu step 3 at Loc 1

Aşağıdaki sorgu öncekine benzer, ancak ProductModel tablosunun yazılan xml sütunu olan Yönergeler sütununda belirtilmiştir. Sorgu, belirli bir ürünün ilk iş merkezi konumundaki tüm üretim adımlarına, <step> öğelere göre yinelenir.

SELECT Instructions.query('
   declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
for $Step in //AWMI:root/AWMI:Location[1]/AWMI:step
      return
           string($Step)
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Önceki sorgudan aşağıdakilere dikkat edin:

  • $Step yineleyici değişkenidir.

  • yol ifadesi, //AWMI:root/AWMI:Location[1]/AWMI:stepgiriş dizisini oluşturur. Bu sıra, ilk <step> öğe düğümünün <Location> öğe düğümü alt öğelerinin dizisidir.

  • İsteğe bağlı koşul yan tümcesi wherekullanılmaz.

  • İfade öğesinden return<step> bir dize değeri döndürür.

Dize işlevi (XQuery), düğümün dize değerini <step> almak için kullanılır.

Kısmi sonuç aşağıdadır:

Insert aluminum sheet MS-2341 into the T-85A framing tool.
Attach Trim Jig TJ-26 to the upper and lower right corners of
the aluminum sheet. ....

Bunlar, izin verilen diğer giriş dizilerine örneklerdir:

DECLARE @x AS XML;

SET @x = '';

SELECT @x.query('
for $a in (1, 2, 3)
  return $a');
-- result = 1 2 3

DECLARE @x AS XML;

SET @x = '';

SELECT @x.query('
for $a in
   for $b in (1, 2, 3)
      return $b
return $a');
-- result = 1 2 3

DECLARE @x AS XML;

SET @x = '<ROOT><a>111</a></ROOT>';

SELECT @x.query('
  for $a in (xs:string( "test"), xs:double( "12" ), data(/ROOT/a ))
  return $a');
-- result test 12 111

SQL Server'da heterojen dizilere izin verilmez. Özellikle, atomik değerlerin ve düğümlerin karışımını içeren dizilere izin verilmez.

Yineleme, bir sonraki sorguda gösterildiği gibi XML biçimlerini dönüştürmede XML yapısı (XQuery) söz dizimi ile birlikte sıklıkla kullanılır.

AdventureWorks örnek veritabanında, tablonun sütununda Instructions depolanan Production.ProductModel üretim yönergeleri aşağıdaki biçimdedir:

<Location LocationID="10" LaborHours="1.2"
            SetupHours=".2" MachineHours=".1">
  <step>describes 1st manu step</step>
   <step>describes 2nd manu step</step>
   ...
</Location>
...

Aşağıdaki sorgu, iş merkezi konum öznitelikleri alt öğe olarak döndürülen öğelere sahip <Location> yeni XML oluşturur:

<Location>
   <LocationID>10</LocationID>
   <LaborHours>1.2</LaborHours>
   <SetupHours>.2</SetupHours>
   <MachineHours>.1</MachineHours>
</Location>
...

Sorgu şu şekildedir:

SELECT Instructions.query('
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        for $WC in /AWMI:root/AWMI:Location
        return
          <Location>
            <LocationID> { data($WC/@LocationID) } </LocationID>
            <LaborHours>   { data($WC/@LaborHours) }   </LaborHours>
            <SetupHours>   { data($WC/@SetupHours) }   </SetupHours>
            <MachineHours> { data($WC/@MachineHours) } </MachineHours>
          </Location>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Önceki sorguda dikkate alınacak noktalara dikkat edin:

  • FLWOR deyimi, belirli bir ürün için bir öğe dizisi <Location> alır.

  • Data işlevi (XQuery) her özniteliğin değerini ayıklamak için kullanılır, böylece sonuçta elde edilen XML'e öznitelik olarak değil metin düğümleri olarak eklenir.

  • yan tümcesindeki RETURN ifade, istediğiniz XML'yi oluşturur.

Bu kısmi bir sonuçdur:

<Location>
  <LocationID>10</LocationID>
  <LaborHours>2.5</LaborHours>
  <SetupHours>0.5</SetupHours>
  <MachineHours>3</MachineHours>
</Location>
<Location>
   ...
<Location>
...

Yan tümcesini let kullanma

değişkenine let başvurarak başvurabileceğiniz yinelenen ifadeleri adlandırmak için yan tümcesini kullanabilirsiniz. Bir let değişkene atanan ifade, sorguda değişkene her başvuruldığında sorguya eklenir. Bu, ifadeye başvuruldıkça deyiminin birçok kez yürütüldüğünü gösterir.

AdventureWorks2025 Veritabanında, üretim yönergeleri gerekli araçlar ve araçların kullanıldığı konum hakkında bilgi içerir. Aşağıdaki sorgu, bir üretim modeli oluşturmak için gereken araçları ve her aracın gerekli olduğu konumları listelemek için yan tümcesini kullanır let .

SELECT Instructions.query('
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        for $T in //AWMI:tool
            let $L := //AWMI:Location[.//AWMI:tool[.=data($T)]]
        return
          <tool desc="{data($T)}" Locations="{data($L/@LocationID)}"/>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Yan tümcesini where kullanma

Bir yinelemenin sonuçlarını filtrelemek için yan tümcesini where kullanabilirsiniz. Bu, sonraki örnekte gösterilmiştir.

Bisiklet üretiminde, üretim süreci bir dizi iş merkezi konumundan geçer. Her iş merkezi konumu, bir dizi üretim adımı tanımlar. Aşağıdaki sorgu yalnızca bir bisiklet modeli üreten ve üçten az üretim adımına sahip olan iş merkezi konumlarını alır. Yani, üçten <step> az öğeye sahiptirler.

SELECT Instructions.query('
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
for $WC in /AWMI:root/AWMI:Location
      where count($WC/AWMI:step) < 3
      return
          <Location >
           { $WC/@LocationID }
          </Location>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Önceki sorguda aşağıdakilere dikkat edin:

  • where anahtar sözcüğü, her iş merkezi konumundaki alt öğe sayısını count()<step saymak için işlevini kullanır.>

  • ifadesi return , yinelemenin sonuçlarından istediğiniz XML'yi oluşturur.

Sonuç şu şekildedir:

<Location LocationID="30"/>

yan tümcesindeki where ifadenin sonucu, belirtilen sırayla aşağıdaki kurallar kullanılarak boole değerine dönüştürülür. Bunlar, tamsayılara izin verilmediği sürece yol ifadelerindeki koşulların kurallarıyla aynıdır:

  1. where İfade boş bir dizi döndürürse, geçerli Boole değeri False olur.

  2. where İfade basit bir Boole türü değeri döndürürse, bu değer geçerli Boole değeridir.

  3. İfade en where az bir düğüm içeren bir dizi döndürürse, geçerli Boole değeri True olur.

  4. Aksi takdirde, statik bir hata oluşturur.

FLWOR'da birden çok değişken bağlama

Giriş dizilerine birden çok değişken bağlayan tek bir FLWOR ifadeniz olabilir. Aşağıdaki örnekte, sorgu yazılmamış bir xml değişkenine karşı belirtilir. FLOWR ifadesi, her <Step> öğedeki ilk <Location> öğe alt öğesini döndürür.

DECLARE @x AS XML;

SET @x = '<ManuInstructions ProductModelID="1" ProductModelName="SomeBike" >
<Location LocationID="L1" >
  <Step>Manu step 1 at Loc 1</Step>
  <Step>Manu step 2 at Loc 1</Step>
  <Step>Manu step 3 at Loc 1</Step>
</Location>
<Location LocationID="L2" >
  <Step>Manu step 1 at Loc 2</Step>
  <Step>Manu step 2 at Loc 2</Step>
  <Step>Manu step 3 at Loc 2</Step>
</Location>
</ManuInstructions>';

SELECT @x.query('
   for $Loc in /ManuInstructions/Location,
       $FirstStep in $Loc/Step[1]
   return
       string($FirstStep)
');

Önceki sorgudan aşağıdakilere dikkat edin:

  • İfade for ve $$Loc değişkenlerini tanımlarFirstStep.

  • two ve /ManuInstructions/Locationifadeleri, $FirstStep in $Loc/Step[1] değerlerinin değerlerine $FirstStep$Locbağlı olmasıyla ilişkilendirilir.

  • ile $Loc ilişkilendirilmiş ifade bir öğe dizisi <Location> oluşturur. Her <Location> öğe için tek $FirstStep bir öğe dizisi <Step> oluşturur.

  • $Loc değişkeniyle ilişkilendirilmiş ifadede $FirstStep belirtilir.

Sonuç şu şekildedir:

Manu step 1 at Loc 1
Manu step 1 at Loc 2

Aşağıdaki sorgu benzerdir, ancak tablonun Yönergeler sütununda ( yazılan xml sütunu) ProductModel belirtilir. XML yapısı (XQuery), istediğiniz XML'yi oluşturmak için kullanılır.

SELECT Instructions.query('
     declare default element namespace "https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
for $WC in /root/Location,
            $S  in $WC/step
      return
          <Step LocationID= "{$WC/@LocationID }" >
            { $S/node() }
          </Step>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Önceki sorguda aşağıdakilere dikkat edin:

  • yan tümcesi for iki değişken $WC tanımlar ve $S. ile $WC ilişkili ifade, bir bisiklet ürün modelinin üretiminde bir dizi iş merkezi konumu oluşturur. değişkenine atanan yol ifadesi, $S içindeki $WCher iş merkezi konum dizisi için bir adım dizisi oluşturur.

  • return deyimi, üretim adımını ve özniteliğini içeren bir <Step> öğesi olan XML'yi LocationID oluşturur.

  • Belirtilen varsayılan öğe ad alanı, sonuçta elde edilen XML'deki tüm ad alanı bildirimlerinin en üst düzey öğede görünmesi için XQuery girişinde kullanılır. Bu, sonucu daha okunabilir hale getirir. Varsayılan ad alanları hakkında daha fazla bilgi için bkz. XQuery'de Ad Alanlarını İşleme.

Kısmi sonuç aşağıdadır:

<Step xmlns=
    "https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
  LocationID="10">
     Insert <material>aluminum sheet MS-2341</material> into the <tool>T-
     85A framing tool</tool>.
</Step>
...
<Step xmlns=
      "https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
    LocationID="20">
        Assemble all frame components following blueprint
        <blueprint>1299</blueprint>.
</Step>
...

Yan tümcesini order by kullanma

XQuery'de sıralama, FLWOR ifadesindeki yan tümcesi kullanılarak order by gerçekleştirilir. Yan tümcesine order by geçirilen sıralama ifadeleri, türleri işleç için gt geçerli olan değerler döndürmelidir. Her sıralama ifadesi tek bir öğeyle tek bir diziyle sonuçlanmalıdır. Varsayılan olarak sıralama artan düzende gerçekleştirilir. İsteğe bağlı olarak her sıralama ifadesi için artan veya azalan düzen belirtebilirsiniz.

Uyarı

SQL Server'da XQuery uygulaması tarafından gerçekleştirilen dize değerleriyle ilgili sıralama karşılaştırmaları her zaman ikili Unicode kod noktası harmanlaması kullanılarak gerçekleştirilir.

Aşağıdaki sorgu, AdditionalContactInfo sütunundan belirli bir müşterinin tüm telefon numaralarını alır. Sonuçlar telefon numarasına göre sıralanır.

USE AdventureWorks2022;
GO

SELECT AdditionalContactInfo.query('
   declare namespace act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes";
   declare namespace aci="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo";
   for $a in /aci:AdditionalContactInfo//act:telephoneNumber
   order by $a/act:number[1] descending
   return $a
') AS Result
FROM Person.Person
WHERE BusinessEntityID = 291;

Atomizasyon (XQuery) işlemi, öğelerini öğesine geçirmeden <önce atomik değerini number>order by alır. işlevini kullanarak data() ifadeyi yazabilirsiniz, ancak bu gerekli değildir.

order by data($a/act:number[1]) descending

Sonuç şu şekildedir:

<act:telephoneNumber xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
  <act:number>333-333-3334</act:number>
</act:telephoneNumber>
<act:telephoneNumber xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
  <act:number>333-333-3333</act:number>
</act:telephoneNumber>

Sorgu girişinde ad alanlarını bildirmek yerine kullanarak bunları WITH XMLNAMESPACESbildirebilirsiniz.

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes' AS act, 'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo' AS aci)
SELECT AdditionalContactInfo.query('
   for $a in /aci:AdditionalContactInfo//act:telephoneNumber
   order by $a/act:number[1] descending
   return $a
') AS Result
FROM Person.Person
WHERE BusinessEntityID = 291;

Öznitelik değerine göre de sıralama yapabilirsiniz. Örneğin, aşağıdaki sorgu, LocationID ve LaborHours özniteliklerinin LaborHours özniteliğine göre azalan düzende sıralandığı yeni oluşturulan <Location> öğeleri alır. Sonuç olarak, en fazla çalışma saati olan iş merkezi konumları ilk olarak döndürülür.

SELECT Instructions.query('
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
for $WC in /AWMI:root/AWMI:Location
order by $WC/@LaborHours descending
        return
          <Location>
             { $WC/@LocationID }
             { $WC/@LaborHours }
          </Location>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Sonuç şu şekildedir:

<Location LocationID="60" LaborHours="4"/>
<Location LocationID="50" LaborHours="3"/>
<Location LocationID="10" LaborHours="2.5"/>
<Location LocationID="20" LaborHours="1.75"/>
<Location LocationID="30" LaborHours="1"/>
<Location LocationID="45" LaborHours=".5"/>

Aşağıdaki sorguda sonuçlar öğe adına göre sıralanır. Sorgu, belirli bir ürünün belirtimlerini ürün kataloğundan alır. Belirtimler öğenin alt <Specifications> öğeleridir.

SELECT CatalogDescription.query('
     declare namespace
 pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
      for $a in /pd:ProductDescription/pd:Specifications/*
     order by local-name($a)
      return $a
    ') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 19;

Önceki sorgudan aşağıdakilere dikkat edin:

  • ifadesi /p1:ProductDescription/p1:Specifications/* öğesinin <Specifications>öğesi alt öğelerini döndürür.

  • İfade, order by (local-name($a)) sırayı öğe adının yerel bölümüne göre sıralar.

Sonuç şu şekildedir:

<Color>Available in most colors</Color>
<Material>Aluminum Alloy</Material>
<ProductLine>Mountain bike</ProductLine>
<RiderExperience>Advanced to Professional riders</RiderExperience>
<Style>Unisex</Style>

Sıralama ifadesinin boş döndürdüğü düğümler, aşağıdaki örnekte gösterildiği gibi sıranın başlangıcına göre sıralanır:

DECLARE @x AS XML;

SET @x = '<root>
  <Person Name="A" />
  <Person />
  <Person Name="B" />
</root>
';

SELECT @x.query('
  for $person in //Person
  order by $person/@Name
  return   $person
');

Sonuç şu şekildedir:

<Person />
<Person Name="A" />
<Person Name="B" />

Aşağıdaki örnekte gösterildiği gibi birden çok sıralama ölçütü belirtebilirsiniz. Bu örnekteki sorgu, öğeleri önce Başlığa ve ardından Yönetici öznitelik değerlerine göre sıralar <Employee> .

DECLARE @x AS XML;

SET @x = '<root>
  <Employee ID="10" Title="Teacher"        Gender="M" />
  <Employee ID="15" Title="Teacher"  Gender="F" />
  <Employee ID="5" Title="Teacher"         Gender="M" />
  <Employee ID="11" Title="Teacher"        Gender="F" />
  <Employee ID="8" Title="Administrator"   Gender="M" />
  <Employee ID="4" Title="Administrator"   Gender="F" />
  <Employee ID="3" Title="Teacher"         Gender="F" />
  <Employee ID="125" Title="Administrator" Gender="F" /></root>';

SELECT @x.query('for $e in /root/Employee
order by $e/@Title ascending, $e/@Gender descending

  return
     $e
');

Sonuç şu şekildedir:

<Employee ID="8" Title="Administrator" Gender="M" />
<Employee ID="4" Title="Administrator" Gender="F" />
<Employee ID="125" Title="Administrator" Gender="F" />
<Employee ID="10" Title="Teacher" Gender="M" />
<Employee ID="5" Title="Teacher" Gender="M" />
<Employee ID="11" Title="Teacher" Gender="F" />
<Employee ID="15" Title="Teacher" Gender="F" />
<Employee ID="3" Title="Teacher" Gender="F" />

Sınırlamalar

Sınırlamalar şunlardır:

  • Sıralama ifadeleri homojen bir şekilde yazılmalıdır. Bu, statik olarak denetlendi.

  • Boş dizilerin sıralanması denetlenemez.

  • en az boş, en büyük boş ve harmanlama anahtar sözcükleri order by desteklenmez