• Nem Talált Eredményt

Az XPath 2.0 funkciói kategóriákra osztva

I. Fejlett Adatbázis Technológiák - Jegyzet

1. Kifejezések

1.4. Az XPath 2.0 funkciói kategóriákra osztva

• Hozzáférhetőségi funkciók: Ezek hozzáférést biztosítanak ahhoz hogy privát módon érhessük el az adatot, egy funkció amely engedélyezi hogy privát módon lekérdezzük és állítsuk be a tulajdonságainak értékét, anélkül hogy közvetlen hozzáférést biztosítana a tulajdonságokat tartalmazó objektumhoz. Egy csak olvasható tulajdonságnak csak egy ilyen függvénye létezik, ami engedélyezi a tulajdonság értékének a lekérdezését.

• fn:node-name(node) – Csomópont neve

• fn:string – Visszaadja a csomópont értékét sztringként.

• fn:data(item [, item,…]) – Szekvenciává alakítja az elemeket,

• Hibák és nyomkövetés: Hibák kiváltása, és megoldása futás közbeni nyomkövetés segítségével.

• fn:error(error, description, object) – Kivált egy kivételt.

• Konstruktorok: Ezek állítják elő az objektum példányokat egy osztályból, vagy definiálnak egy típust.

• xs:date(), xs:string(), xs:Name(), xs:token()

• Numerikus függvények: Mint bármely programozási nyelvben, egy numerikus függvény végez valamilyen konverziót illetve kalkulációt, amely után egy számot ad eredményül. Számos numerikus operátor elérhető az XPath használata közben. Rengeteg ezek közül úgy mint a „numeric-add”, elérhető a megszokottabb szimbolikus használati formája is(+).

• fn:round(num) - Kerekítő függvény.

• fn:abs(num) – Abszolút érték függvény.

• fn:number(arg) – Sztringből numerikus típussá konvertál.

• Szöveges függvények: A műveletek általában szövegen hajtják végre, és legtöbbször ugyanilyen típusú a visszatérési érték is, de nem minden esetben.

• fn:concat(string [, string..]) – Összefűzi a sztringeket.

• fn:string-length([ | string]) – A sztring hossza, vagy ha nincs megadva paraméter akkor az aktuális csomóponté.

• fn:starts-with(string1, string2)/ fn:ends-with(string1, string2)

• fn:contains(string1, string2) – Tartalmazza e az adott zstringet.

• fn:replace(string, pattern, replace) – Lecseréli a sztringben az előfordulásokat.

• URI függvények: URI-kat dolgoznak fel, illetve módosítanak. Az egyetlen függvény ebben a szekcióban:

• fn:resolve-uri(relative, base) – Feloldja a relatív URI-kat abszolúttá.

• Boolean függvények

• fn:boolean(arg) – Sztring, numerikus illetve csomópont értékek boolean értéke.

• fn:not(arg) – A boolean függvény inverze.

• Idő és dátum funkciók

• fn:dateTime(date, time) – Egy TimeStamp típusú objektumot ad vissza.

• fn:year-from-date(date) – Az adott dátumtól számított időtartam években. Hasonló formában létezik hónapokra, napokra is.

• fn:hours-from-time(time) - Az adott időponttól számított időtartam órákban. Hasonló formában létezik percekre, másodpercekre is.

• fn:adjust-dateTime-to-timezone(datetime, timezone) – Egy timestamp objektumot adott időzónának megfelelőre konvertál.

• Léteznek dátumok összegzését, kivonását, hasonlítását szolgáló függvények is.

• QName funkciók: (Qualified Name) A QName egy korlátozott név. Egy QName tartalmaz egy névtér URI-t.

A QName egy opcionális előtag és egy kettőspont után következik a „helyi” név vagy egy URI és a lokális vagy attribútum név.

• fn:QName() – Visszadja a QName értékét az adott csomópontnak.

• fn:local-name-from-QName() – A lokális nevet adja vissza a QName attribútumból.

• fn:namespace-uri-from-QName() – Névtérrel és URI-val tér vissza.

• Csomópont függvények

• fn:name([nodeset]) – Az aktuális csomópont neve, vagy a csomópont kollekció első eleme.

• fn:root([node]) – Visszaadja a gyökér elemet.

• op:is-same-node – Igazat ad vissza, ha a két csomópont egyenlő.

• Szekvencia funkciók: A szekvencia ténylegesen egy lista a nem létező vagy még lehetségesen ismétlődő elemek egy szülő csomóponton belül. A szekvencia ennek következtében egy kollekció. Szekvencia függvények alkalmazhatóak egy egyszerű kollekcióra teljes egészében, vagy a kollekció valamely tagjára.

• fn:count(collection) - Kollekció elemeinek száma

• fn:max(collection) - Kollekció elemeinek maximuma

• fn:avg(collection) – Kollekció elemeinek átlaga

• fn:empty(collection) – Igazat ad vissza ha üres a kollekció.

• fn:exists(collection) – Nem üres kollekciókra igazat ad.

• Tartalmi funkciók: Ezek a funkciók a jelentésekkel dolgoznak, így a meta adatokat dolgozzák fel

• fn:last() – Megtalálja az utolsó elemet a kollekcióban.

• fn:current-date()/fn:current-time() – Aktuális dátum illetve időpont.

• fn:implicit-timezone() – Megtalálja az időzónára vonatkozó értéket.

• Egyéb típusú függvények: 64bites számokon alapuló operátorok, XML jelölésekre vonatkozó függvények és operátorok. Az XML jelölések(notation) egy formája az XML-nek, amely dialektus specifikus, és nagyon speciális alkalmazásokhoz lett készítve XML-ben úgy, mint a MathXML, CML. A speciális XML dialektus jelölések szabványokat is fektetnek le, és a regionális szemantikát alkalmazzák az egyébként általános XML adathoz.

6. fejezet - XQuery

Az XQuery olyan az XML-nél, mint az SQL az adatbázisoknál, adatok kérdezhetünk le és módosíthatunk a segítségével. 2006 óta W3C ajánlás. Arra lett tervezve hogy bármit lekérdezzünk ami XML adatként jelenik meg, még relációs adatbázisban tárolt XML adattípus struktúrát is. Lényegében adatmodellből és az adatmodellen használható lekérdező operátorokból áll.

Inkább leíró, mint procedurális programozási nyelv, csakúgy, mint az SQL. Míg egy procedurális programozási nyelv lépésről lépésre ( akár a különböző programkód sorok között egymásnak értékeket átadva és visszakapva) halad a feldolgozásban a probléma megoldásához, addig egy leíró programozási nyelv egyszerűen definiál határvonalakat, feltételeket és megszorításokat ( a számítógépre hagyva, hogy keressen valamilyen megoldást amely megfelel a specifikált megszorításoknak). Egy leíró nyelv sokkal magasabb szintű, mind egy procedurális programozási nyelv, ami az XQuery esetében egy hibrid megoldáshoz vezet.

Az XQuery átvizsgálja az XML dokumentumot (vagy egy részét), felhasználja a megszorításokat a lekérdezéshez (úgy mint szűrés, predikátumok), és vissza adja azokat az adatokat amelyek illeszkednek a lekérdezés által specifikált határvonalaknak, feltételeknek és megszorításoknak. A megoldás egy részhalmaza az eredetileg vizsgált XML dokumentumnak, XML formában. Technikailag, az XQuery mindenhol használható ahol az XML is. Az XML célja hogy létrehozzon egy univerzálisan érthető, rendszer független adat forrást, így az XQuery követve a formát, megkísérel egy univerzálisan használható XML dokumentum lekérdező nyelvet létrehozni.

Az XPath és XQuery ugyanazokat a funkciókat és operátorokat használja, és az adat modell is közös. Valójában az XQuery XPath kifejezésekkel végez lekérdezéseket XML dokumentumokon. Ezen felül elágaztató utasításokat használhatunk,változókat, ciklusokat, függvényeket deklarálhatunk.

XQuery alapjai

A legfontosabb tény, hogy az XQuery nem XML-ben íródott, bár a lekérdezések beágyazhatóak XSL stílus lapokkal. XQuery parancsok pedig akár HTML fájlokba is beágyazhatók. Hét különböző fajta XQuery csomópont létezik: elem, attribútum, névtér, feldolgozási információ, megjegyzés, dokumentum.

• Atomi érték: Egy szöveges érték, nincs szülő vagy gyermek csomópontja.

• Darab érték: Ez lehet atomi érték vagy csomópont.

• Szülő: Egy csomópont szülőjére hivatkozik, általában csomópontokra és nem atomi értékekre utal.

• Gyermek: Ellentéte a szülőnek, ahol a csomópontnak 0 vagy több csomópontja lehet. Egy csomópont aminek lehet gyermeke, de nincs, egy üres csomópontra hivatkozik.

• Testvér: Egy csomópont abban a kollekcióban amelynek ugyanaz a szülő csomópontja.

• Ős: Bármely csomópont az érvényes csomópont felett a fában.

• Leszármazott: Bármely csomópont az érvényes csomópont alatt.

1. XQuery alapszabályok

Néhány általános szabály:

• A parancsokban és kódokban megkülönböztetjük a kis és nagy betűket, csak úgy, mint az XML esetében.

• Minden csomópontnak érvényesnek kell lennie, mint XML név.

• Változó definiálása a let kulcsszó és a $ karakter segítségével történik, például let $változónév.

• Az elágaztató utasítások szintaktikája a következő:

if(…)thenelse ...

• Többszörös értékek hasonlítása szabványos aritmetikai operátorokkal történik úgy, mint =, !=, >, <=

Összehasonlítás: egy XQuery kifejezés egy elem szekvencián operál, ennek megfelelően az összehasonlító operátorok is elfogadnak szekvenciákat. Emiatt fontos figyelnünk arra a sajátos viselkedésre, ahogy az XQuery interpretálja ezt (szemben az egyszerű elemekkel):

e1 θ e2 ahol

θ ∈ {=,!=,<,<=,>=,>}

minidig igaz eredményre ( true() ) vezet,

ha bármely két e1 és e2 eleme között található igaz összehasonlítás.

• Csomópontok összehasonlítása: is - azonosság, dokumentum sorrend - <<, >>

<x>42</x> eq <x>42</x> => true()

<x>42</x> is <x>42</x> => false() let $a := <x><y/></x>

return $a << $a/y => true()

• Aritmetika: az általános várakozások teljesülnek, az operátorok: +, -, *, div, idiv

Annyi megjegyzéssel, hogy az operátorok először atomizálják az operandust és csak ezután alakítják a megfelelő típusra. Ha bármelyik operandus is (), akkor az eredmény is ().

<x>1</x> + 41 => 42.0 () * 42 => ()

(1,2) - (2,3) => (típus összeférhetetlenség) x-42 => ./child::x-42 (ehelyett x - 42) x/y => ./child::x/child::y (ehelyett x div y)

• Adattípus tesztelhető, beépített operátorok segítségével. Az instance of igazat ad vissza, ha a vizsgált elem az adott típusú:

// miután csak elemeken működik, a fenti két utasítás hozza azt létre typeswitch($patient)

case element(intenzív) return "sürgős"

case element(fertőző) return "elkülönítendő"

default return "paciens"

Miután az XQuery esetén az elemszekvenciák mindig kiegyenesítődnek, csak ezen konstruktorok segíthetnek a hierarchikus adatok előállításában. ( Ez egyben alkalmassá is teszi arra, hogy esetlegesen XSLT

transzformációkat váltsunk ki XQuery segítségével. ) Az XQuery a hét csomópont típusnak megfelelően hét különböző konstruktorral rendelkezik. Mindegyik esetében létezik

• direkt konstruktor: szintaxisuk teljesen megegyezik az XML natív szintaxisával. Bármely jól formázott XML töredék egyben egy érvényes XQuery kifejezés is. (az egyetlen megjegyzés, hogy a CDATA szakaszok szöveges csomópontokká válnak, ezt nem őrzi meg)

• kiértékelt konstruktor: kulcsszó vezeti be és mind a neve, mind az értéke dinamikusan számítható az új csomópontnak.

A legjelentősebb konstruktorok:

• dokumentum: egy teljesen új XML dokumentum létrehozása (document {}) document {

Ügyeljünk arra, hogy létező XML dokumentumoknál mindig van egy láthatatlan document gyökér elem. Ha csak XML töredékekkel dolgozunk, akkor ennek szerepét a legkülső elem tölti be, azaz egy

<x><y/></x>/* kifejezés csak egy <y/> elemet eredményez.

• elem:

• egy új elem létrehozása történhet direkt módon:

<x><![CDATA[foo & bar]]></x> ≡ <x>foo &amp; bar</x>

// a CDATA nem őrződik meg

Az elem neve konstans, de a tartalma mindazonáltal lehet dinamikusan kiértékelhető. Ezt XQuery-ben a a {} közé fogott kifejezéssel adhatjuk meg. A dinamikus konstrukciók menet közben kiértékelődnek, szemben a közvetlenül megadottakkal, melyek viszont nem. Azaz:

<tag>3*3</tag> eredménye pontosan az lesz amit írtunk: <tag>3*3</tag>

ellenben ha dinamikus konstrukciót használunk:

<tag>{3*3}</tag> az eredmény: <tag>9</tag>

Fontos megjegyezni, hogy ezek ugyan egymásba ágyazhatóak, de ha erre nem figyelünk, akkor könnyen túlsiklunk azon, hogy egy dinamikus konstruktoron belül már újabb kiértékelésbe nem kezd bele, azaz:

<tag>{<int>3*3</int>}</tag> csupán egy <int>3*3</int> rész eredményez.

Ha ezt tovább akarjuk vinni, akkor az alábbi módon tehetjük:

<tag>{

} }

</newPerson>

A második dinamikus kifejezésben felsoroltuk az új csomópontokat vesszővel elválasztva, amivel egy csomópontokból álló szekvenciát adunk meg. Ezen csomópontokon belül viszont már újabb elemekre nincs szükségünk, ezért az adott információhoz nem magát a csomópontot kértük vissza, hanem csak a tartalmazott adatot, amelyet a data függvény segítségével nyertünk ki a csomópontból.

• dinamikusan létrehozva:

element {kifejezés_névhez} {kifejezés_értékhez }

element { string-join(("foo","bar"),"-") } { 40+2 } => <foo-bar>42</foo-bar>

Ez a konstrukció igazán jól alátámasztja, hogy valóban felhasználható az XQuery az XSLT bizonyos fokú kiváltására. Például egy szótár segítségével a dokumentumban használt elemneveket lecseréljük a célnyelvnek megfelelően:

// a szótár

<entry word="address">

<variant lang="de">Adresse</variant>

<variant lang="it">indirizzo</variant>

</entry>

// és ahogy lecseréljük az elemneveket megőrizve a tartalmát (+ attribútumait):

element

• közvetlen módon: karakterek az elem tartalmában vagy CDATA szekcióval. Az elem szöveges értékének meghatározása a szokásos atomizáción megy végig, melyeket sztringgé konvertál és szóköz segítségével összefűz.

• dinamikusan:

text {kifejezés}

if (empty(e)) then ()

else text { string-join(for $i in data(e) return string($i)," ") }

A dinamikus konstruktorok közül az elem konstruktor a legrugalmasabb. A tartalmat megadó szekvencia elemei bármilyen csomóponttípusba tartozhatnak. Az összeállítás során az alábbiakat végzi el a feldolgozó:

1. egymást követő karakter literálok egy szöveges csomóponttá válnak.

2. a dinamikus részek kiértékelődnek: {}

3. a szomszédos atomi értékek sztringgé konvertálódnak és szóköz segítségével összefűzésre kerülnek 4. a másolt csomópontok tartalommal együtt másolásra kerülnek és új identitást kapnak

5. szomszédos szöveges csomópontok összefűzésre kerülnek. Az üresek ("") pedig eldobódnak.

// Tippeljük meg mennyi lesz a kifejezés értéke (azaz mennyi csomópont készül?):

count(

<x>Negyvenkettő{40 + 2}{ "pi",3.1415,<y><z/></y>,("","!")[1] }</x>/node() )

A létrejövő csomópont:

x (a szöveges csomópont értéke: "Negyvenkettő42pi 3.1415")

/ \ text y | z

A tartalom létrehozásánál egy dologra kell mindenképp figyelni: jól-formázott tartalomra van szükség. (Azaz nem egyezhet meg attribútumok neve, és meg kell előzniük minden más tartalmat.) Ezen felül akármilyen tartalmat is hozunk létre, az mindig dokumentumsorrendet is jelent.

3. Iteráció: FLWOR

Ez a kifejezés a „for” ciklus egy formája. Emlékezzünk vissza, hogy az XPath implicit módon biztosítja ez a '.' környezeti elem aktualizálásával egy cs/e kifejezésben. Az XQuery ezt programozott formában, a for ciklus segítségével biztosítja egy kollekció minden elemére, más szóval engedélyezi ugyanazt a folyamatot lefuttatni minden elemre egy kollekcióból. A FLWOR szó a „For, Let, Where, Order by, Return” szavak kezdőbetűiből tevődik össze.

Nézzük meg mire is használhatóak ezek a záradékok:

for: A segítségével bejárhatjuk egy szekvencia csomópont elemeit.

let: Változókat deklarálhatunk vele.

where: A „for” után használatos, akárcsak az SQL-ben, az ebben szereplő feltételeknek eleget tevő csomópontok kerülnek kiválasztásra

order by: Rendezi a „for” által kiválasztott elemeket a megadott csomópontok alapján.

return: Visszatér a megadott atomi értékkel vagy csomóponttal.

Ez azt jelenti hogy a „for” ciklus teszi lehetővé egy egész kollekció elemenkénti feldolgozását. A „where”

feltétel szűrési lehetőségeket ad, hogy csak a szükséges elemeket dolgozzuk fel. Az „order” feltétel rendezettséget biztosít az eredményhalmazban, amelyet a „return” ad vissza. A „return” irányítja a speciális elemeket, amelyek a „for” ciklusból lettek visszaadva.

A FLWOR összetettsége révén lehetővé teszi:

• egymásba ágyazást,

• szekvenciák összekapcsolását (join),

• csoportosítást,

• dokumentumsorrenden túli rendezést az order by segítségével.

Explicit iteráció használatának szintaktikája:

for $v [at $p] in e1

return e2

A szintaktika egy plusz lehetőség is ad, opcionálisan elérhetjük az aktuálisan feldolgozott elem pozícióját is (a szintaktikában p-vel jelölve). Azaz ha az e1 szekvencia egy (x1, ..., xn) elemsorozatot alkot, akkor az e2 n-szer kerül kiértékelésre, ahol $v kötődik az aktuális xi-hez (és p pedig i-hez). Az eredmények pedig egy szekvenciába lesznek összefogva.

// elem kettesek visszaadása for $x in (3,2,1)

return ($x,"*") => (3,"*",2,"*",1,"*") // eredményhez egy plusz elem hozzáfűzése for $x in (3,2,1)

Ezeknél azért összetettebb problémák is megoldhatóak a függvények használatával:

// Fa mélységének meghatározása

// (!) Figyeljük meg a levélelemek összeszedésének módját (!) max( for $i in cs/descendant-or-self::*[not(*)]

return count($i/ancestor::*) ) // minden második elem kinyerése

// ( emlékezzünk vissza a szekvenciák egymásba ágyazhatóságára és a 0 igazságértékére ) for $i at $p in e vagy szebben írva: for $i at $p in e

return if ($p mod 2) where ($p mod 2) then e[$p] return e[$p]

else ()

Visszatérve még egyszer az explicit és implicit iteráció közötti különbségre, fontos megjegyezni a kontextus elem körülötti eltéréseket is:

Ránézésre mindkettő ugyanazt eredményezni, de a különbség a kontextus elem illetve elemek között van. Míg az XPath minden egyes lépés (/) esetén lecseréli a kontextus elemet, addig az XQuery esetén mindvégig ugyanaz marad!

3.1. A rendezés sajátosságai

A FLWOR kifejezések alapvetően a szekvencia eredeti elemsorrendjét követve készítik el az eredmény szekvenciát. Ennek felülbírálására az SQL-ből jól ismert order by záradék használható minimális kiegészítéssel.

Használhatóak a jól ismert [ascending|descending] módosítók, és akár több elem szerint is rendezhetőek

(ekkor vesszővel elválasztva kell felsorolni). Ami a kiegészítés, hogy megadható az üres szekvenciát adó kifejezések helye: vagy a lista elején vagy a végén szerepeljenek: [empty greatest|least].

Példák:

for $i in doc("companys.xml")/persons/person[id lt 10]

where $i/@sex = "female"

A rendezésnél még egy dolgoz figyelembe kell venni. Tekintsük az alábbi példát:

let $authors := for $a in doc("books.xml")//author order by $a/last, $a/first

return $a return $authors/last

Azaz szeretnénk a szerzőket vezetéknév szerint rendezett listában látni. A probléma az lesz, hogy az eredmény továbbra is a dokumentumsorrendnek megfelelően érkezik, mert a / és a // mindig eszerint működik. Ez szintén egy érdekes működés, de jó számolni vele, hogy a / és a // mindig felülbírálja az order by sorrendjét!

A helyes megoldás:

for $a in doc("books.xml")//author order by $a/last, $a/first

return $a/last

A rendezés kapcsán még egy dolog merülhet fel: az azonos értékek kezelése. Alapvetően ha csomópontok ismétlődnek azonos tartalommal az a rendezés szempontjából irreleváns, egymás után következnek dokumentumsorrendben és így kerülnek át az eredmény szekvenciába. Mindazonáltal ha szeretnénk ezeket az ismétlődő részfákat kiszedni, akkor az XQuery rendelkezik egy distinct-values() függvénnyel, amely a csomópontok értékét összehasonlítva már csak az egyedieket engedi tovább.

for $l in distinct-values(doc("books.xml")//author/last) return <last>{ $l }</last>

// Ugyanezt megtehetjük kicsit összetettebben is, már teljes nevet vizsgálva:

let $a := doc("books.xml")//author for $l in distinct-values($a/last),

$f in distinct-values($a[last=$l]/first) return

Miután minden FLWOR kifejezés egy n-esen (tuple) dolgozik, ezért szükségszerűen ezeket meg kell adni. Erre az XQuery két lehetőséget is biztosít. Ami eddig nem derülhetett ki egyértelműen, hogy a for mellett a let is erre szolgál. Ennek értelmében legalább az egyiknek szerepelnie kell minden XQuery kifejezésben legalább egyszer, arra pedig semmilyen megkötés nincs, hogy melyiknek is. Továbbmenve, a sorrendjükre sincs semmilyen megkötés, azaz akármilyen variációt elfogad az XQuery.

Ami a legfontosabb, hogy átlássuk miként is állítják elő ezen elem n-eseket a for és let kulcsszavak. A for esete tisztább, mert ha megadok egy szekvenciát, akkor annak minden elemére végrehajtódik:

for $i in (1, 2, 3)

Ezzel szemben a let egy elemként tekinti az értékét:

let $i := (1, 2, 3)

return <tuple><i>{ $i }</i><j>{ $j }</j></tuple>

eredménye:

<tuple><i>1</i><j>1 2 3</j></tuple>

<tuple><i>2</i><j>1 2 3</j></tuple>

<tuple><i>3</i><j>1 2 3</j></tuple>

egy sokkal életszerűbb példán tekintve:

megadjuk minden egyes paciens esetén a kezelőorvosok számát for $b in doc("patients.xml")//patient

let $c := $b/therapist

return <patient>{ $b/name, <count>{ count($c) }</patient>}</book>

A változók használata mellett még egy nagyon fontos jellemzőjüket meg kell említeni:

megváltoztathatatlanok. A let által kötött változókat úgy tekinthetjük, mint nevesített értékeket és épp ezért nem módosíthatóak. Az alábbi példa jól demonstrálja az intuitív használatot felülbíráló viselkedést:

Ahogy elképzelnénk imperatív módon: Ahogy meg kell oldani XQuery

Egyes lekérdezéseknél meg kell állapítanunk, hogy a sorozat legalább egy eleme megfelel-e a feltételnek, vagy akár minden eleme megfelel-e. Ezt tehetjük meg a kvantorokkal. Egzisztenciális kvantorral azt vizsgáljuk, hogy legalább egy tétel megfelel-e egy állapotnak. Az alábbi lekérdezés egy egzisztenciális kvantort mutat:

// megkapjuk azon cégeket, melyeknek van bejegyzett magyarországi telefonjuk for $x in doc("companys.xml")/company

where some $y in $x/phone satisfies

starts-with($y/text(),"06") or starts-with($y/text(),"+36") return $x/name

Ezzel szemben az univerzális kvantor azt vizsgálja, hogy a szekvencia összes eleme kielégíti-e a feltételt. Átírva az előző példát:

// megkapjuk azon cégeket, melyeknek CSAK magyarországi bejegyzett telefonjuk van for $x in doc("companys.xml")/company

where every $y in $x/phone satisfies

starts-with($y/text(),"06") or starts-with($y/text(),"+36") return $x/name

Az univerzális kvantor esetén fontos megjegyezni, hogy olyan esetekben, ahol ezt üres szekvenciára használjuk, ott mindig igazat kapunk, mert az üres szekvencia effektív igazságértéke igaz (azaz olyan cégek is felkerülhetnek a listára, amelyeknél nincs kitöltött phone érték - mind üres)

4. Függvények

A lekérdezések írásánál el tudunk kérni egy szintet, amikor már annyira komplexszé tudnak válni, hogy

A lekérdezések írásánál el tudunk kérni egy szintet, amikor már annyira komplexszé tudnak válni, hogy