Bagikan melalui


Pernyataan dan Iterasi FLWOR (XQuery)

Berlaku untuk:SQL Server

XQuery mendefinisikan sintaks iterasi FLWOR. FLWOR adalah akronim dari for, , letwhere, order by, dan return.

Pernyataan FLWOR terdiri dari bagian-bagian berikut:

  • Satu atau beberapa klausa FOR yang mengikat satu atau beberapa variabel iterator ke urutan input.

    Urutan input dapat berupa ekspresi XQuery lainnya seperti ekspresi XPath. Keduanya adalah urutan simpul atau urutan nilai atomik. Urutan nilai atom dapat dibangun menggunakan literal atau fungsi konstruktor. Simpul XML yang dibuat tidak diizinkan sebagai urutan input di SQL Server.

  • Klausa opsional let . Klausa ini menetapkan nilai ke variabel yang diberikan untuk iterasi tertentu. Ekspresi yang ditetapkan dapat berupa ekspresi XQuery seperti ekspresi XPath, dan dapat mengembalikan urutan simpul atau urutan nilai atomik. Urutan nilai atom dapat dibangun dengan menggunakan fungsi literal atau konstruktor. Simpul XML yang dibuat tidak diizinkan sebagai urutan input di SQL Server.

  • Variabel iterator. Variabel ini dapat memiliki pernyataan jenis opsional dengan menggunakan as kata kunci.

  • Klausa opsional where . Klausa ini menerapkan predikat filter pada iterasi.

  • Klausa opsional order by .

  • Ekspresi return . Ekspresi dalam return klausul membangun hasil pernyataan FLWOR.

Misalnya, kueri <Step> berikut mengulangi elemen di lokasi manufaktur pertama dan mengembalikan nilai string simpul:<Step>

declare @x 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)  
')  

Ini adalah hasilnya:

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

Kueri berikut ini mirip dengan yang sebelumnya, kecuali yang ditentukan terhadap kolom Instruksi, kolom xml yang diketik, dari tabel ProductModel. Kueri berulang di semua langkah manufaktur, <step> elemen, di lokasi pusat kerja pertama untuk produk tertentu.

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  

Perhatikan hal berikut ini dari kueri sebelumnya:

  • $Step adalah variabel iterator.

  • Ekspresi jalur, //AWMI:root/AWMI:Location[1]/AWMI:step, menghasilkan urutan input. Urutan ini adalah urutan turunan <step> simpul elemen dari node elemen pertama.<Location>

  • Klausa predikat opsional, where, tidak digunakan.

  • Ekspresi return mengembalikan nilai string dari <step> elemen .

Fungsi string (XQuery) digunakan untuk mengambil nilai string simpulstep<>.

Ini adalah hasil parsial:

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. ....         

Ini adalah contoh urutan input tambahan yang diizinkan:

declare @x xml  
set @x=''  
SELECT @x.query('  
for $a in (1, 2, 3)  
  return $a')  
-- result = 1 2 3   
  
declare @x 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 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  

Di SQL Server, urutan heterogen tidak diperbolehkan. Secara khusus, urutan yang berisi campuran nilai atom dan simpul tidak diperbolehkan.

Iterasi sering digunakan bersama dengan sintaks Konstruksi XML dalam mengubah format XML, seperti yang diperlihatkan dalam kueri berikutnya.

Dalam database sampel AdventureWorks, instruksi manufaktur yang disimpan di kolom Instruksi tabel Production.ProductModel memiliki formulir berikut:

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

Kueri berikut membuat XML baru yang memiliki <Location> elemen dengan atribut lokasi pusat kerja yang dikembalikan sebagai elemen turunan:

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

Ini adalah kueri:

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  

Perhatikan hal berikut ini dari kueri sebelumnya:

  • Pernyataan FLWOR mengambil urutan <Location> elemen untuk produk tertentu.

  • Fungsi data (XQuery) digunakan untuk mengekstrak nilai setiap atribut sehingga akan ditambahkan ke XML yang dihasilkan sebagai simpul teks alih-alih sebagai atribut.

  • Ekspresi dalam klausa RETURN membuat XML yang Anda inginkan.

Ini adalah hasil parsial:

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

Menggunakan let Clause

Anda dapat menggunakan let klausul untuk memberi nama ekspresi berulang yang dapat Anda rujuk dengan merujuk ke variabel . Ekspresi yang let ditetapkan ke variabel dimasukkan ke dalam kueri setiap kali variabel direferensikan dalam kueri. Ini berarti bahwa pernyataan dijalankan sebanyak ekspresi direferensikan.

AdventureWorks2022 Dalam database, instruksi manufaktur berisi informasi tentang alat yang diperlukan dan lokasi tempat alat digunakan. Kueri berikut menggunakan klausul let untuk mencantumkan alat yang diperlukan untuk membangun model produksi, serta lokasi di mana setiap alat diperlukan.

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  

Menggunakan klausul where

Anda dapat menggunakan where klausa untuk memfilter hasil iterasi. Ini diilustrasikan dalam contoh berikutnya ini.

Dalam pembuatan sepeda, proses manufaktur melalui serangkaian lokasi pusat kerja. Setiap lokasi pusat kerja menentukan urutan langkah-langkah manufaktur. Kueri berikut hanya mengambil lokasi pusat kerja yang memproduksi model sepeda dan memiliki kurang dari tiga langkah manufaktur. Artinya, mereka memiliki kurang dari tiga <step> elemen.

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  

Perhatikan hal berikut ini di kueri sebelumnya:

  • Kata where kunci menggunakan fungsi count() untuk menghitung jumlah <step> elemen anak di setiap lokasi pusat kerja.

  • return Ekspresi membuat XML yang Anda inginkan dari hasil iterasi.

Ini adalah hasilnya:

<Location LocationID="30"/>   

Hasil ekspresi dalam klausa dikonversi where ke nilai Boolean dengan menggunakan aturan berikut, dalam urutan yang ditentukan. Ini sama dengan aturan untuk predikat dalam ekspresi jalur, kecuali bilangan bulat tidak diizinkan:

  1. where Jika ekspresi mengembalikan urutan kosong, nilai Boolean yang efektif adalah False.

  2. where Jika ekspresi mengembalikan satu nilai jenis Boolean sederhana, nilai tersebut adalah nilai Boolean yang efektif.

  3. where Jika ekspresi mengembalikan urutan yang berisi setidaknya satu simpul, nilai Boolean yang efektif adalah True.

  4. Jika tidak, itu menimbulkan kesalahan statis.

Beberapa Pengikatan Variabel dalam FLWOR

Anda dapat memiliki satu ekspresi FLWOR yang mengikat beberapa variabel ke urutan input. Dalam contoh berikut, kueri ditentukan terhadap variabel xml yang tidak dititip. Ekspresi FLOWR mengembalikan turunan elemen pertama <Step> di setiap <Location> elemen.

declare @x 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)  
')  

Perhatikan hal berikut ini dari kueri sebelumnya:

  • for Ekspresi mendefinisikan $Loc dan $FirstStep variabel.

  • Ekspresi two , /ManuInstructions/Location dan $FirstStep in $Loc/Step[1], berkorelasi dalam nilai $FirstStep bergantung pada nilai $Loc.

  • Ekspresi yang terkait dengan $Loc menghasilkan urutan <Location> elemen. Untuk setiap <Location> elemen, $FirstStep menghasilkan urutan satu <Step> elemen, satuton.

  • $Loc ditentukan dalam ekspresi yang terkait dengan $FirstStep variabel.

Ini adalah hasilnya:

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

Kueri berikut ini serupa, kecuali bahwa kueri tersebut ditentukan terhadap kolom Instruksi, kolom xml yang diketik, dari tabel ProductModel. Konstruksi XML (XQuery) digunakan untuk menghasilkan XML yang Anda inginkan.

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  

Perhatikan hal berikut ini di kueri sebelumnya:

  • Klausa for mendefinisikan dua variabel, $WC dan $S. Ekspresi yang terkait dengan $WC menghasilkan urutan lokasi pusat kerja dalam pembuatan model produk sepeda. Ekspresi jalur yang $S ditetapkan ke variabel menghasilkan urutan langkah-langkah untuk setiap urutan lokasi pusat kerja di $WC.

  • Pernyataan pengembalian membangun XML yang memiliki <Step> elemen yang berisi langkah manufaktur dan LocationID sebagai atributnya.

  • Namespace elemen default deklarasikan digunakan dalam prolog XQuery sehingga semua deklarasi namespace dalam XML yang dihasilkan muncul di elemen tingkat atas. Ini membuat hasilnya lebih mudah dibaca. Untuk informasi selengkapnya tentang namespace default, lihat Menangani Namespace di XQuery.

Ini adalah hasil parsial:

<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>  
...  

Menggunakan urutan berdasarkan Klausul

Pengurutan dalam XQuery dilakukan dengan menggunakan order by klausa dalam ekspresi FLWOR. Ekspresi pengurutan yang diteruskan ke order by klausul harus mengembalikan nilai yang jenisnya valid untuk operator gt . Setiap ekspresi pengurutan harus menghasilkan satuton urutan dengan satu item. Secara default, pengurutan dilakukan dalam urutan naik. Anda dapat secara opsional menentukan urutan naik atau menurun untuk setiap ekspresi pengurutan.

Catatan

Pengurutan perbandingan pada nilai string yang dilakukan oleh implementasi XQuery di SQL Server selalu dilakukan dengan menggunakan kolase titik kode Unicode biner.

Kueri berikut mengambil semua nomor telepon untuk pelanggan tertentu dari kolom AdditionalContactInfo. Hasilnya diurutkan menurut nomor telepon.

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;  

Perhatikan bahwa proses Atomisasi (XQuery) mengambil nilai atom elemen><numbersebelum meneruskannya ke .order by Anda dapat menulis ekspresi dengan menggunakan fungsi data(), tetapi itu tidak diperlukan.

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

Ini adalah hasilnya:

<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>  

Alih-alih mendeklarasikan namespace dalam prolog kueri, Anda bisa mendeklarasikannya dengan menggunakan WITH XMLNAMESPACES.

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;  

Anda juga dapat mengurutkan berdasarkan nilai atribut. Misalnya, kueri berikut mengambil elemen yang baru dibuat <Location> yang memiliki atribut LocationID dan LaborHours yang diurutkan menurut atribut LaborHours dalam urutan menurun. Akibatnya, lokasi pusat kerja yang memiliki jam kerja maksimum dikembalikan terlebih dahulu.

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;  

Ini adalah hasilnya:

<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"/>  

Dalam kueri berikut, hasilnya diurutkan menurut nama elemen. Kueri mengambil spesifikasi produk tertentu dari katalog produk. Spesifikasinya adalah anak-anak dari elemen .<Specifications>

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;  

Perhatikan hal berikut ini dari kueri sebelumnya:

  • Ekspresi /p1:ProductDescription/p1:Specifications/* mengembalikan turunan elemen dariSpecifications<> .

  • Ekspresi order by (local-name($a)) mengurutkan urutan menurut bagian lokal dari nama elemen.

Ini adalah hasilnya:

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

Simpul di mana ekspresi pengurutan mengembalikan kosong diurutkan ke awal urutan, seperti yang ditunjukkan dalam contoh berikut:

declare @x 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  
')  

Ini adalah hasilnya:

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

Anda dapat menentukan beberapa kriteria pengurutan, seperti yang diperlihatkan dalam contoh berikut. Kueri dalam contoh ini mengurutkan <Employee> elemen terlebih dahulu menurut Judul lalu menurut nilai atribut Administrator.

declare @x 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  
')  

Ini adalah hasilnya:

<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" />  

Batasan Implementasi

Ini adalah batasannya:

  • Ekspresi pengurutan harus dititik secara homogen. Ini diperiksa secara statis.

  • Mengurutkan urutan kosong tidak dapat dikontrol.

  • Kata kunci order by paling kosong, kosong terbesar, dan kolase di tidak didukung

Lihat Juga

Ekspresi XQuery