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 FOR klausa 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 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)
');

Berikut 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 simpul<step>.

Berikut hasil parsialnya:

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 lain yang diizinkan:

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

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

Iterasi sering digunakan bersama dengan sintaks konstruksi XML (XQuery) dalam mengubah format XML, seperti yang ditunjukkan pada kueri berikutnya.

Dalam database sampel AdventureWorks, instruksi manufaktur yang disimpan di Instructions kolom Production.ProductModel tabel 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>
...

Berikut kuerinya:

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 pertimbangan berikut dari kueri sebelumnya:

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

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

  • Ekspresi dalam RETURN klausa 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>
...

let Gunakan klausa

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.

AdventureWorks2025 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, dan 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;

where Gunakan klausa

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 count() fungsi untuk menghitung jumlah <step> elemen anak di setiap lokasi pusat kerja.

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

Berikut 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 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)
');

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.

Berikut 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 ProductModel tabel. 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.

Berikut hasil parsialnya:

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

order by Gunakan klausa

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 gt operator. 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;

Proses Atomisasi (XQuery) mengambil nilai atom dari <number> elemen sebelum meneruskannya ke .order by Anda dapat menulis ekspresi dengan menggunakan data() fungsi , tetapi itu tidak diperlukan.

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

Berikut 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 dapat 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;

Berikut 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 dari<Specifications> .

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

Berikut hasilnya:

<Color>Available in most colors</Color>
<Material>Aluminum 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 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
');

Berikut 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 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
');

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

Keterbatasan

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