Pernyataan dan Iterasi FLWOR (XQuery)
Berlaku untuk:SQL Server
XQuery mendefinisikan sintaks iterasi FLWOR. FLWOR adalah akronim dari for
, , let
where
, 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 dalamreturn
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:
where
Jika ekspresi mengembalikan urutan kosong, nilai Boolean yang efektif adalah False.where
Jika ekspresi mengembalikan satu nilai jenis Boolean sederhana, nilai tersebut adalah nilai Boolean yang efektif.where
Jika ekspresi mengembalikan urutan yang berisi setidaknya satu simpul, nilai Boolean yang efektif adalah True.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><number
sebelum 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