I am new to XQuery (coming from SQL) and I am trying to write a query that selects all results that do not exist in another table.
More specifically I am using this XML database: https://www.dbis.informatik.uni-goettingen.de/Mondial/mondial.xml and I am trying to select all countries that do NOT have any islands
XML Query:
let $islands := doc("mondial.xml")/mondial/island/located/data(@country)
for $country in doc("mondial.xml")/mondial/country
let $c_code := $country/data(@car_code)
let $c_name := data($country/name)
where not($c_code=$islands)
order by $c_name
return $c_name
Same query but in SQL:
SELECT name
FROM Country
WHERE code
NOT IN (SELECT country FROM geo_island);
(relational schema of equivalent SQL database: https://www.dbis.informatik.uni-goettingen.de/Mondial/mondial-RS.pdf )
The correct amount of countries I should get in my results is 120, but instead I get 210 countries. What did I do wrong?
EDIT: If I didnt make it clear before: I wrote the SQL query before I wrote the XQuery query. I am simply trying to translate SQL queries to XQuery queries.
The countries an island is part of are in /mondial/island/@country
, not in /mondial/island/located/@country
. See for example the entry for Ireland :
<island id="island-Ireland" country="IRL GB" sea="sea-Irische_See sea-Atlantic">
<name>Ireland</name>
<islands>British Isles</islands>
<located country="GB" province="prov-gb-12"/>
<area>84421</area>
<latitude>53.5</latitude>
<longitude>-7.8</longitude>
<elevation>1041</elevation>
</island>
Both Ireland the country and the UK (ie Northern Ireland) are on the island of Ireland, so there are two space-separated entries in /mondial/island[name = 'Ireland']/@country
.
You can use fn:tokenize($string[, $separator])
to get all single countries and (for performance) get all unique island-having countries with fn:distinct-values($sequence)
. The rest can stay the same:
let $doc := doc("mondial.xml")
let $islands := distinct-values($doc/mondial/island/@country/tokenize(.))
for $country in $doc/mondial/country
let $c_code := $country/data(@car_code)
let $c_name := data($country/name)
where not($c_code=$islands)
order by $c_name
return $c_name
This now returns 120 countries as expected.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.