Sophie

Sophie

distrib > Fedora > 14 > x86_64 > media > updates > by-pkgid > 71d40963b505df4524269198e237b3e3 > files > 855

virtuoso-opensource-doc-6.1.4-2.fc14.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
 <head profile="http://internetalchemy.org/2003/02/profile">
  <link rel="foaf" type="application/rdf+xml" title="FOAF" href="http://www.openlinksw.com/dataspace/uda/about.rdf" />
  <link rel="schema.dc" href="http://purl.org/dc/elements/1.1/" />
  <meta name="dc.title" content="14. RDF Data Access and Data Management" />
  <meta name="dc.subject" content="14. RDF Data Access and Data Management" />
  <meta name="dc.creator" content="OpenLink Software Documentation Team ;&#10;" />
  <meta name="dc.copyright" content="OpenLink Software, 1999 - 2009" />
  <link rel="top" href="index.html" title="OpenLink Virtuoso Universal Server: Documentation" />
  <link rel="search" href="/doc/adv_search.vspx" title="Search OpenLink Virtuoso Universal Server: Documentation" />
  <link rel="parent" href="rdfandsparql.html" title="Chapter Contents" />
  <link rel="prev" href="rdfgraphsecurity.html" title="RDF Graphs Security" />
  <link rel="next" href="rdfrdfviewgnr.html" title="Automated Generation of RDF Views over Relational Data Sources" />
  <link rel="shortcut icon" href="../images/misc/favicon.ico" type="image/x-icon" />
  <link rel="stylesheet" type="text/css" href="doc.css" />
  <link rel="stylesheet" type="text/css" href="/doc/translation.css" />
  <title>14. RDF Data Access and Data Management</title>
  <meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8" />
  <meta name="author" content="OpenLink Software Documentation Team ;&#10;" />
  <meta name="copyright" content="OpenLink Software, 1999 - 2009" />
  <meta name="keywords" content="" />
  <meta name="GENERATOR" content="OpenLink XSLT Team" />
 </head>
 <body>
  <div id="header">
    <a name="rdfviews" />
    <img src="../images/misc/logo.jpg" alt="" />
    <h1>14. RDF Data Access and Data Management</h1>
  </div>
  <div id="navbartop">
   <div>
      <a class="link" href="rdfandsparql.html">Chapter Contents</a> | <a class="link" href="rdfgraphsecurity.html" title="RDF Graphs Security">Prev</a> | <a class="link" href="rdfrdfviewgnr.html" title="Automated Generation of RDF Views over Relational Data Sources">Next</a>
   </div>
  </div>
  <div id="currenttoc">
   <form method="post" action="/doc/adv_search.vspx">
    <div class="search">Keyword Search: <br />
        <input type="text" name="q" /> <input type="submit" name="go" value="Go" />
    </div>
   </form>
   <div>
      <a href="http://www.openlinksw.com/">www.openlinksw.com</a>
   </div>
   <div>
      <a href="http://docs.openlinksw.com/">docs.openlinksw.com</a>
   </div>
    <br />
   <div>
      <a href="index.html">Book Home</a>
   </div>
    <br />
   <div>
      <a href="contents.html">Contents</a>
   </div>
   <div>
      <a href="preface.html">Preface</a>
   </div>
    <br />
   <div class="selected">
      <a href="rdfandsparql.html">RDF Data Access and Data Management</a>
   </div>
    <br />
   <div>
      <a href="rdfdatarepresentation.html">Data Representation</a>
   </div>
   <div>
      <a href="rdfsparql.html">SPARQL</a>
   </div>
   <div>
      <a href="sparqlextensions.html">Extensions</a>
   </div>
   <div>
      <a href="rdfgraphsecurity.html">RDF Graphs Security</a>
   </div>
   <div class="selected">
      <a href="rdfviews.html">Linked Data Views over RDBMS Data Source</a>
    <div>
        <a href="#rdfviewsintro" title="Introduction">Introduction</a>
        <a href="#rdfviewrationale" title="Rationale">Rationale</a>
        <a href="#rdfviewquadmapatternsvalueandiriclasses" title="Quad Map Patterns, Values and IRI Classes">Quad Map Patterns, Values and IRI Classes</a>
        <a href="#rdfviewconfiguringrdfstorages" title="Configuring RDF Storages">Configuring RDF Storages</a>
        <a href="#rdfviewtranslationofpatterns" title="Translation Of SPARQL Triple Patterns To Quad Map Patterns">Translation Of SPARQL Triple Patterns To Quad Map Patterns</a>
        <a href="#rdfviewdescribingsourcerelationaltables" title="Describing Source Relational Tables">Describing Source Relational Tables</a>
        <a href="#rdfviewiriusingfunction" title="Function-Based IRI Classes">Function-Based IRI Classes</a>
        <a href="#rdfconnvarsiniriclasses" title="Connection Variables in IRI Classes">Connection Variables in IRI Classes</a>
        <a href="#rdfviewbijandreturns" title="Lookup Optimization -- BIJECTION and RETURNS Options">Lookup Optimization -- BIJECTION and RETURNS Options</a>
        <a href="#rdfviewsubclasses" title="Join Optimization -- Declaring IRI Subclasses">Join Optimization -- Declaring IRI Subclasses</a>
        <a href="#rdfmetadatarecovery" title="RDF Metadata Maintenance and Recovery">RDF Metadata Maintenance and Recovery</a>
        <a href="#splitrdfview" title="Split RDF View">Split RDF View</a>
        <a href="#rdfviewsrcur" title="RDF views and recursive FK relationships">RDF views and recursive FK relationships</a>
    </div>
   </div>
   <div>
      <a href="rdfrdfviewgnr.html">Automated Generation of RDF Views over Relational Data Sources</a>
   </div>
   <div>
      <a href="rdfviewsenterpr.html">Examples of Linked Data Views</a>
   </div>
   <div>
      <a href="rdfinsertmethods.html">RDF Insert Methods in Virtuoso</a>
   </div>
   <div>
      <a href="virtuososponger.html">RDFizer Middleware (Sponger)</a>
   </div>
   <div>
      <a href="virtuosospongerfacetinstall.html">Virtuoso Faceted Browser Installation and configuration</a>
   </div>
   <div>
      <a href="virtuosospongerfacent.html">Virtuoso Faceted Web Service</a>
   </div>
   <div>
      <a href="rdfiridereferencing.html">Linked Data</a>
   </div>
   <div>
      <a href="rdfsparqlrule.html">Inference Rules &amp; Reasoning</a>
   </div>
   <div>
      <a href="rdfsparqlgeospat.html">RDF and Geometry</a>
   </div>
   <div>
      <a href="rdfperformancetuning.html">RDF Performance Tuning</a>
   </div>
   <div>
      <a href="rdfnativestorageproviders.html">RDF Data Access Providers (Drivers)</a>
   </div>
   <div>
      <a href="rdfgraphreplication.html">RDF Graph Replication</a>
   </div>
    <br />
  </div>
  <div id="text">
    <a name="rdfviews" />
    <h2>14.5. Linked Data Views over RDBMS Data Source</h2>
<p>
RDF Views map relational data into RDF and allow customizing RDF representation of locally stored RDF data.
To let SPARQL clients access relational data as well as physical RDF graphs in a single query, we introduce a declarative Meta Schema Language for mapping SQL Data to RDF Ontologies.
As a result, all types of clients can efficiently access all data stored on the server.
The mapping functionality dynamically generates RDF Data Sets for popular ontologies such as SIOC, SKOS, FOAF, and ATOM/OWL without disruption to the existing database infrastructure of Web 1.0 or Web 2.0 solutions.
RDF views are also suitable for declaring custom representation for RDF triples, e.g. property tables, where one row holds many single-valued properties.
</p>
<a name="rdfviewsintro" />
    <h3>14.5.1. Introduction</h3>
<p>
The Virtuoso RDF Views meta schema is a built-in feature of Virtuoso&#39;s SPARQL to SQL translator.
It recognizes triple patterns that refer to graphs for which an alternate representation is declared and translates these into SQL accordingly.
The main purpose of this is evaluating SPARQL queries against existing relational databases.
There exists previous work from many parties for rendering relational data as RDF and opening it to SPARQL access.
We can mention D2RQ, SPASQL, Squirrel RDF, DBLP and others.
The Virtuoso effort differs from these mainly in the following:
</p>
<ul>
<li>Integration with a triple store.
Virtuoso can process a query for which some triple patterns will go to local or remote relational data and some to local physical RDF triples.
</li>
      <li>SPARQL query can be used in any place where SQL can.
Database connectivity protocols are neutral to the syntax of queries they transmit, thus any SQL client, e.g. JDBC, ODBC or XMLA application, can send SPARQL queries and fetch result sets.
Moreover, a SQL query may contain SPARQL subqueries and SPARQL expressions may use SQL built-in functions and stored procedures.
</li>
      <li>Integration with SQL.
Since SPARQL and SQL share the same run time and query optimizer, the query compilation decisions are always made with the best knowledge of the data and its location.
This is especially important when mixing triples and relational data or when dealing with relational data distributed across many outside databases.
</li>
      <li>No limits on SPARQL.
It remains possible to make queries with unspecified graph or predicate against mapped relational data, even though these may sometimes be inefficient.
</li>
      <li>Coverage of the whole relational model.
Multi-part keys etc. are supported in all places.
</li>
</ul>
<br />
<a name="rdfviewrationale" />
    <h3>14.5.2. Rationale</h3>
<p>
Since most of the data that is of likely use for the emerging semantic web is stored in relational databases, the argument for exposing this to SPARQL access is clear.
We note that historically, SQL access to relational data has essentially never been given to the public outside of the organization.
If programmatic access to corporate IS has been available to partners or the public, it has been through dynamic web pages or more recently web services.
There are reasons of performance, security, maintainability and so forth for this.
</p>
    <p>
The culture of the emerging semantic web is however taking a different turn.
Since RDF and OWL offer a mergeable and queryable model for heterogeneous data, it is more meaningful and maintainable to expose selected data for outside query than it would be with SQL.
Advances in hardware make this also less of a performance issue than it would have been in the client-server database era.
</p>
    <p>
In the context of Virtuoso, since Virtuoso is originally a virtual/federated database, incorporating SPARQL to relational mapping is an evident extension of the product&#39;s mission as a multi-protocol, multi-platform connector between information systems.
</p>
<br />
<a name="rdfviewquadmapatternsvalueandiriclasses" />
    <h3>14.5.3. Quad Map Patterns, Values and IRI Classes</h3>
<p>
In the simplest sense, any relational schema can be rendered into RDF by converting all primary keys and foreign keys into IRI&#39;s, assigning a predicate IRI to each column, and an rdf:type predicate for each row linking it to a RDF class IRI corresponding to the table.
Then a triple with the primary key IRI as subject, the column IRI as predicate and the column&#39;s value as object is considered to exist for each column that is neither part of a primary or foreign key.
</p>
    <p>
Strictly equating a subject value to a row and each column to a predicate is often good but is too restrictive for the general case.
</p>
<ul>
<li>Multiple triples with the same subject and predicate can exist.
</li>
      <li>A single subject can get single-valued properties from multiple tables or in some cases stored procedures.
</li>
      <li>An IRI value of a subject or other field of a triple can be composed from more than one SQL value, these values may reside in different columns, maybe in different joined tables.
</li>
      <li>Some table rows should be excluded from mapping.
</li>
    </ul>
<p>
Thus in the most common case the RDF meta schema should consist of independent transformations; the domain of each transformation is a result-set of some SQL <strong>SELECT</strong> statement and range is a set of triples.
The <strong>SELECT</strong> that produce the domain is quite simple: it does not use aggregate functions, joins and sorting, only inner joins and <strong>WHERE</strong> conditions.
There is no need to support outer joins in the RDF meta schema because NULLs are usually bad inputs for functions that produce IRIs.
In the rare cases when NULLs are OK for functions, outer joins can be encapsulated in SQL views.
The range of mapping can be described by a SPARQL triple pattern: a pattern field is a variable if it depends on table columns, otherwise it is a constant.
Values of variables in the pattern may have additional restrictions on datatypes, when datatypes of columns are known.
</p>
    <p>
This common case of an RDF meta schema is implemented in Virtuoso, with one adjustment.
Virtuoso stores quads, not triples, using the graph field (G) to indicate that a triple belongs to some particular application or resource.
A SPARQL query may use quads from different graphs without large difference between G and the other three fields of a quad.
E.g., variable <strong>?g</strong> in expression <strong>GRAPH ?g {...}</strong> can be unbound.
SPARQL has special syntax for &quot;graph group patterns&quot; that is convenient for sets of triple patterns with a common graph, but it also has shorthands for common subject and predicate, so the difference is no more than in syntax.
There is only one feature that is specific for graphs but not for other fields: the SPARQL compiler can create restrictions on graphs according to <strong>FROM</strong> and <strong>FROM NAMED</strong> clauses.
</p>
    <p>
Virtuoso RDF Views should offer the same flexibility with the graphs as SPARQL addressing physical triples.
A transformation cannot always be identified by the graph used for ranges because graph may be composed from SQL data. The key element of the meta schema is a &quot;<strong>quad map pattern</strong>&quot;.
A simple quad map pattern fully defines one particular transformation from one set of relational columns into triples that match one SPARQL graph pattern.
The main part of quad map pattern is four declarations of &quot;<strong>quad map values</strong>&quot;, each declaration specifies how to calculate the value of the corresponding triple field from the SQL data.
The pattern also lists boolean SQL expressions that should be used to filter out unwanted rows of source data (and to join multiple tables if source columns belong to different tables).
There are also quad map patterns that group together similar quad patterns but do not specify any real transformation or even prevent unwanted transformations from being used, they are described in &quot;Grouping Map Patterns&quot; below.
</p>
    <p>
Quad map values refer to schema elements of two further types: &quot;IRI classes&quot; and &quot;literal classes&quot;.
</p>
<div class="note">
      <div class="notetitle">Note:</div>
      <p>In SQL, adding a new view can not break anything. This is because SQL lacks the ability of querying &quot;everything&quot; so data sources are always specified. This is not true for SPARQL, so please treat <strong>any</strong> metadata manipulation as potentially destructive operation. If an RDF storage is supposed to be used by more than one application then these applications should be tested together, not one after other, and they should be installed/upgraded on live database in the very same order as they were installed/upgraded on instrumental machine during testing. Always remember that these applications share RDF tables so they may interfere.</p>
    </div>
<a name="rdfviewiriclasses" />
    <h4>14.5.3.1. IRI Classes</h4>
<p>
An IRI class declares that a column or set of columns gets converted into a IRI in a certain way.
The conversion of this sort can be declared revertible (bijection) so an IRI can be parsed into original SQL values; this is useful when some equality of an IRI constant and a calculated IRI can be replaced with an equality of a parse result of a constant and an SQL column that is index criteria or simply faster.
In addition, the SPARQL optimizer will eliminate redundant conversions if one IRI class is explicitly declared as a subclass of another.
The most flexible declaration for conversion consists of specifying functions that assemble and disassemble from IRI into its constituent parts.
This is overkill for typical conversions so it is possible to specify only one sprintf-style format string such that <strong>sprintf()</strong> SQL function will print an IRI using this format and <strong>sprintf_inverse()</strong> will be able to parse it back.
</p>
    <p>The use of <strong>sprintf_inverse()</strong> assumes that the format does not contain fragments like <strong>&#39;%s%s&#39;</strong> that make it impossible to separate parts of IRI from each other.
</p>
    <p>
In the following, we shall map the Virtuoso users and user roles system tables into the SIOC ontology.
</p>
<div>
      <pre class="programlisting">
create iri class oplsioc:user_iri &quot;http://myhost/sys/user?id=%d&quot;
  (in uid integer not null) .
create iri class oplsioc:group_iri &quot;http://myhost/sys/group?id=%d&quot;
  (in gid integer not null) .
create iri class oplsioc:membership_iri
  &quot;http://myhost/sys/membership?super=%d&amp;sub=%d&quot;
  (in super integer not null, in sub integer not null) .
create iri class oplsioc:dav_iri &quot;http://myhost%s&quot;
  (in path varchar) .
</pre>
    </div>
<p>
These IRI classes are used for mapping data from the <strong>DB.DBA.SYS_USERS</strong> and <strong>DB.DBA.SYS_ROLE_GRANTS</strong> system tables that are defined in Virtuoso as follows:
</p>
<div>
      <pre class="programlisting">
create table DB.DBA.SYS_USERS (
  U_ID                integer not null unique,
  U_NAME              char (128) not null primary key,
  U_IS_ROLE           integer default 0,
  U_FULL_NAME         char (128),
  U_E_MAIL            char (128) default &amp;quot;,
  U_ACCOUNT_DISABLED  integer default 1,
  U_DAV_ENABLE        integer default 0,
  U_SQL_ENABLE        integer default 1,
  U_HOME              varchar (128),
. . .
 );
</pre>
    </div>
<p>
Single record in <strong>DB.DBA.SYS_USERS</strong> corresponds to a plain user or a group (role).
Users and roles are collectively named &quot;grantees&quot;. Thus a role may be granted to another role or to a user account.
A role grant may be direct (explicit) or assigned by recursion.
</p>
<div>
      <pre class="programlisting">
create table SYS_ROLE_GRANTS (
  GI_SUPER   integer,
  GI_SUB     integer,
  GI_DIRECT  integer default 1,
. . .
  primary key (GI_SUPER, GI_SUB, GI_DIRECT));
</pre>
    </div>
<p>One IRI class usually corresponds to one ontology class, because similar things are usually called similarly.
One may wish to use identifiers of ontology classes as identifiers of related IRI classes, to not remember double number of names, e.g. <strong>create IRI class mybank:XpressXfer</strong> for subjects that will have <strong>rdf:type</strong> property <strong>mybank:XpressXfer</strong> made by mapping. That is technically possible but proven to become inconvenient and misleading as application evolves. While RDF types tend to persist, IRI classes may change over time or same subject may get more than one name via more than one IRI class, say, for exports to different systems. It is found to be more convenient to compose names of IRI classes by adding some common prefixes or suffixes to RDF classes (or to table names), say, write <strong>create IRI class mybank:XpressXfer_iri</strong>.</p>
<br />
<a name="rdfviewliteralclasses" />
    <h4>14.5.3.2. Literal Classes</h4>
<p>
A &quot;literal class&quot; declares that a column or set of columns gets converted into a literal instead of an IRI.
More precisely, the result of conversion can be <strong>IRI_ID</strong> so it represents an IRI, but in current version of Virtuoso this is supported only for some internal built-in literal classes, not for classes declared by the user.
So for user-defined literal class the result of the conversion is an RDF literal even if it is a string representation of a valid IRI.
</p>
    <p>
In any case, a literal class can be used only in quad map values of O fields, because Virtuoso does not support literal values as subjects.
</p>
    <p>
A special case of literal class is the identity class that converts a value from <strong>varchar</strong> column into an untyped literal and value from column of any other SQL datatype into a typed literal with type from XMLSchema set, i.e. <strong>xsd:integer</strong>, <strong>xsd:dateTime</strong> and so on.
Columns of types <strong>ANY</strong> and <strong>IRI_ID</strong> are not supported.
</p>
    <p>
The SPARQL optimizer knows that RDF literal types are pairwise disjoint so literal classes that produce literals of different types are known to be pairwise disjoint.
The optimizer will replace a join on two disjoint literal classes with an empty statement, to simplify the resulting query.
</p>
<br />
<a name="rdfviewsimplequadmappatterns" />
    <h4>14.5.3.3. Simple Quad Map Patterns</h4>
<p>
The following declaration of quad map pattern is self-explanatory. The line for <strong>object</strong> uses identity literal class so there&#39;s no need to specify its name.
</p>
<div>
      <pre class="programlisting">
graph      &lt;http://myhost/sys&gt;
subject    oplsioc:user_iri (DB.DBA.SYS_USERS.U_ID)
predicate  foaf:email
object     DB.DBA.SYS_USERS.U_E_MAIL
</pre>
    </div>
<p>
The description language also supports SPARQL-style notation that contains less keywords and eliminates duplicate graphs, subjects and predicates.
The following add two patterns with constant graph IRI <strong>&lt;http://myhost/sys&gt;</strong> and subjects are made from column <strong>DB.DBA.SYS_USERS.U_ID</strong> by <strong>oplsioc:user_iri</strong>.
</p>
<div>
      <pre class="programlisting">
graph &lt;http://myhost/sys&gt;
  {
    oplsioc:user_iri (DB.DBA.SYS_USERS.U_ID)
      a sioc:user ;
      oplsioc:name DB.DBA.SYS_USERS.U_FULL_NAME .
  }
</pre>
    </div>
<br />
<a name="rdfviewassigningnamestoquadmappatterns" />
    <h4>14.5.3.4. Assigning Names To Quad Map Patterns</h4>
<p>
In real applications, quad map patterns should be named, for schema manipulation and keeping debug info readable.
Thus it is much better to rewrite the previous example as
</p>
<div>
      <pre class="programlisting">
create virtrdf:SysUsers as graph &lt;http://myhost/sys&gt;
  {
    oplsioc:user_iri (DB.DBA.SYS_USERS.U_ID)
      a sioc:user
          as virtrdf:SysUserType-User;
      oplsioc:name DB.DBA.SYS_USERS.U_FULL_NAME
          as virtrdf:SysUsersFullName .
  }
</pre>
    </div>
<p>
Using these names, one may later write, say, <strong>drop quad map virtrdf:SysUserType-User</strong>.
</p>
    <p>
One name, <strong>virtrdf:DefaultQuadMap</strong> is reserved.
It is an internal quad map pattern used to access &quot;native-form&quot; quads from <strong>DB.DBA.RDF_QUAD</strong>:
</p>
<div>
      <pre class="programlisting">
create virtrdf:DefaultQuadMap as
graph rdfdf:default-iid-nonblank (DB.DBA.RDF_QUAD.G)
subject rdfdf:default-iid (DB.DBA.RDF_QUAD.S)
predicate rdfdf:default-iid-nonblank (DB.DBA.RDF_QUAD.P)
object rdfdf:default (DB.DBA.RDF_QUAD.O)
</pre>
    </div>
<p>
IRI classes from <strong>rdfdf:...</strong> namespace are also reserved.
</p>
<br />
<a name="rdfviewgroupingmappatterns" />
    <h4>14.5.3.5. Grouping Map Patterns</h4>
<p>
The previous example actually contains three map patterns, not two.
The name <strong>virtrdf:SysUsers</strong> refers to a &quot;<strong>group map pattern</strong>&quot; that does not define any real transformation of relational data into RDF but helps organize quad map patterns into a tree.
Group may contain both quad map patterns and other groups.
A group can be manipulated as a whole, e.g. <strong>drop quad map virtrdf:SysUsers</strong> will remove all three map patterns.
</p>
<br />
<br />

<a name="rdfviewconfiguringrdfstorages" />
    <h3>14.5.4. Configuring RDF Storages</h3>
<p>
&quot;<strong>Quad Storage</strong>&quot; is a named set of quad map patterns.
The declaration <strong>define input:storage storage-name</strong> states that a SPARQL query will be executed using only quad patterns of the given quad storage.
Declarations of IRI classes, literal classes and quad patterns are shared between all quad storages of an RDF meta schema but every quad storage contains only a subset of all available quad patterns.
Two quad storages are always defined:
</p>
<ul>
<li>A <strong>virtrdf:default</strong> one usually consists of everything (all user-relational mappings plus <strong>virtrdf:DefaultQuadMap</strong> for &quot;native-form&quot; quads from <strong>DB.DBA.RDF_QUAD</strong>)
</li>
      <li>A <strong>virtrdf:empty</strong> storage refers solely to <strong>DB.DBA.RDF_QUAD</strong> and can not be altered.
</li>
    </ul>
<p>
Three statements for manipulating storages are
</p>
<ul>
<li>
        <strong>create quad storage storage-name { quad-map-decls } .</strong>
</li>
      <li>
        <strong>alter quad storage storage-name { quad-map-decls-or-drops } .</strong>
</li>
      <li>
        <strong>drop quad storage storage-name . </strong>
</li>
    </ul>
<p>
A map pattern can be created only as a part of <strong>create quad storage</strong> or <strong>alter quad storage</strong> statement, so initially it is used by exactly one storage.
It can be imported to some other storage using directive <strong>create map-id using storage source-storage</strong>. E.g., declarations of many storages create <strong>virtrdf:DefaultQuadMap</strong> using storage <strong>virtrdf:DefaultQuadStorage</strong>.
</p>
    <p>
Only a &quot;top-level&quot; quad map pattern (standalone or a whole group with descendants) can be imported, member of a group can not.
The import directive also can not be a part of some group declaration.
</p>
    <p>
The directive <strong>drop quad map map-name</strong> removes a map from one storage when it appears inside <strong>alter quad storage</strong> statement.
Otherwise it removes the map from all storages.
There exists garbage collection for quad map patterns, so any unused map is immediately deleted.
A group is deleted with all its descendants.
</p>
<br />
<a name="rdfviewtranslationofpatterns" />
    <h3>14.5.5. Translation Of SPARQL Triple Patterns To Quad Map Patterns</h3>
<p>
When a SPARQL query is compiled into SQL using a quad storage, every triple pattern should become a subquery that retrieves data from relational tables.
This subquery is an <strong>UNION ALL</strong> of joins generated from appropriate quad map patterns.
The complete SQL query is composed from these basic subqueries.
Thus the first operation of the SQL generation for a triple pattern is searching for quad map patterns that may in principle produce triples that match the triple pattern.
</p>
    <p>
The more restrictions contained in the triple pattern the fewer quad map patterns will be used.
A triple pattern <strong>graph ?g { ?s ?p ?o }</strong> is common enough to invoke all data transformations of the storage.
A triple pattern <strong>graph &lt;g&gt; { ?s &lt;p&gt; &lt;o&gt; }</strong> will usually intersect with the range of only one quad map.
Sometimes it is possible to prove that the storage can not contain any data that matches the given triple pattern, hence zero number of members of <strong>UNION ALL</strong> will result in constantly empty result-set.
</p>
<p>The search for quad maps for a given pair of triple pattern and quad map storage is quite simple.
The storage is treated as a tree of map patterns where quad map patterns are leafs, grouping patterns are inner nodes and the whole storage is also treated as a grouping pattern that specify no fields and contains all top-level map patterns of the storage.
</p>
<p>
The tree is traversed from the root, left to right, non-leaf vertex are checked before their children.
The check of a vertex consists of up to four field checks, for G, S, P and O.
Every field check compares the field definition in the vertex and the corresponding field in the triple pattern, G and G, S and S and so on.
Note that a non-leaf vertex defines less than four of its fields, e.g., the root vertex does not define any of its fields and top-level <strong>graph map { ... }</strong> defines only graph.
Checks are performed only for defined fields and return one of three values: &quot;failed&quot;, &quot;passed&quot;, &quot;full match&quot;, according to the following rules:
</p>
<table class="data">
      <caption>Table: 14.5.5.1. Matching Triple Field and Vertex Field</caption>

<tr>
<th class="data">Field of vertex</th>
        <th class="data">Field in triple pattern</th>
        <th class="data">Result</th>
</tr>

<tr>
        <td class="data">constant</td>
        <td class="data">same constant</td>
        <td class="data">full match</td>
      </tr>
<tr>
        <td class="data">constant</td>
        <td class="data">different constant</td>
        <td class="data">failed</td>
      </tr>
<tr>
        <td class="data">constant</td>
        <td class="data">variable of same type</td>
        <td class="data">passed</td>
      </tr>
<tr>
        <td class="data">constant</td>
        <td class="data">variable of different type</td>
        <td class="data">failed</td>
      </tr>
<tr>
        <td class="data">quad map value</td>
        <td class="data">constant of same type</td>
        <td class="data">full match</td>
      </tr>
<tr>
        <td class="data">quad map value</td>
        <td class="data">constant of different type</td>
        <td class="data">failed</td>
      </tr>
<tr>
        <td class="data">quad map value of type X</td>
        <td class="data">variable, X or subtype of X</td>
        <td class="data">full match</td>
      </tr>
<tr>
        <td class="data">quad map value of type X</td>
        <td class="data">variable, supertype of X</td>
        <td class="data">passed</td>
      </tr>
<tr>
        <td class="data">quad map value of type X</td>
        <td class="data">variable, type does not intersect with X</td>
        <td class="data">failed</td>
      </tr>


</table>
    <br />
<p>
If any of the checks fails, the vertex and all its children are excluded from the rest of processing.
Otherwise, if all four fields are defined for the quad map pattern, the map is added to the list of matching map patterns.
The difference between &quot;passed&quot; and &quot;full match&quot; is significant only if the map is declared with <strong>option (exclusive)</strong>
If all performed checks return &quot;full match&quot; and <strong>option (exclusive)</strong> is set then the traverse of the tree is stopped as soon as all children of the vertex are traversed.
The most typical use of this option is when the application developer is sure that all triples of a graph belong to his application and they come from his own quad map patterns, not from <strong>DB.DBA.RDF_QUAD</strong>.
This is to prevent the SPARQL compiler from generating redundant subqueries accessing <strong>DB.DBA.RDF_QUAD</strong>.
The declaration may look like
</p>
<div>
      <pre class="programlisting">
create quad storage &lt;mystorage&gt;
  {
    graph &lt;mygraph&gt; option (exclusive) { . . . }
    create virtrdf:DefaultQuadMap
      using storage virtrdf:DefaultQuadStorage .
  }
</pre>
    </div>
<p>
Exclusive patterns make the order of declarations important, because an exclusive declaration may &quot;throw a shadow&quot; on declarations after it.
Consider a database that have a special table RDF_TYPE that caches all RDF types of all subjects in all graphs.
Consider two declarations: all triples from graph <strong>&lt;http://myhost/sys&gt;</strong> and all triples with <strong>rdf:type</strong> predicate, both exclusive:
</p>
<div>
      <pre class="programlisting">
graph &lt;http://myhost/sys&gt; option (exclusive)
  {
    . . . # mapping of DB.DBA.SYS_USERS as in previous examples.
  }
graph rdfdf:default-iid-nonblank (DB.DBA.RDF_TYPE.G)
subject rdfdf:default-iid (DB.DBA.RDF_TYPE.S)
predicate rdf:type
object rdfdf:default (DB.DBA.RDF_TYPE.O)
option (exclusive)
</pre>
    </div>
<p>
The order of these declarations dictates that triple pattern
</p>
<div>
      <pre class="programlisting">
graph &lt;http://myhost/sys&gt; {?s rdf:type ?o}
</pre>
    </div>
<p>
is compiled using only quad map patterns of the graph declaration, ignoring second declaration (and of course ignoring default mapping rule, if any).
An explicit <strong>option (order N)</strong> at the end of quad map pattern will tweak the priority.
By default, order will grow from 1000 for the first declaration in the statement to 1999 for the last, explicit configuration is especially useful to make order persistent to <strong>alter storage</strong> statements.
</p>
<p>
The <strong>option (exclusive)</strong> trick is ugly, low-level and prone to cause compilation errors after altering storage declarations.
When misused, it is as bad as &quot;red cut&quot; in PROLOG, but one must use this trick to build scalable storages.
</p>
<p>The <strong>option (exclusive)</strong> helps the SPARQL compiler to prepare better SQL queries, but sometimes it is &quot;too exclusive&quot;. For instance, if a grouping quad map pattern specify only quad map value for graph and no other fields then making it exclusive prohibits the use of all declarations of the storage after that one. Sometimes it is better to notify compiler that quads made by the given quad map pattern are supposed to be different from all quads made by declarations listed after the given one.</p>

<p>Consider an application that exports users&#39; personal data
as graphs whose IRIs looks like
<strong>http://www.example.com/DAV/home/</strong>username<strong>/RDF/personal/</strong>;
the application makes a query and a triple pattern is proven to be
restrictive enough to filter out all quads that are not similar to
quads generated by the given quad map pattern (say, the graph is
constant
<strong>http://www.example.com/DAV/home/JohnSmith/RDF/personal/</strong>). The
application do not hope to find any quads that match the pattern but
made by other applications, because graphs named like in the pattern
are supposed to be solely for this single purpose; if, say,
DB.DBA.RDF_QUAD occasionally contains some quads with graph equal to
<strong>http://www.example.com/DAV/home/JohnSmith/RDF/personal/</strong>
then they can be ignored.</p>

<p>Under this circumstances, the quad map pattern may have <strong>option (soft exclusive)</strong>. That grants a permission to the compiler to ignore rest of storage as soon as it is proven that the triple pattern can not access quads that does not match the pattern. So if that is proven then the pattern is exclusive and it makes the query faster; when unsure, the compiler work like there is no option at all.</p>


<div class="note">
      <div class="notetitle">Note:</div>
      <p>The <strong>option (exclusive)</strong> can be used as
a security measure, <strong>option (soft exclusive)</strong> can
not. Say, if an financial application exports its data as a single
graph <strong>http://www.example.com/front-office/cash/</strong>
using <strong>exclusive</strong> then the query that explicitly
refers to that graph will never access any quads written by the
attacker into DB.DBA.RDF_QUAD using same graph IRI. The use of
<strong>soft exclusive</strong> gives no such protection. From the
compiler&#39;s perspective, the <strong>option (soft
exclusive)</strong> is a hint that may be ignored, not an
unambiguous order.</p>
    </div>

<p>
There is one exception from the rules described above.
This exception is for <strong>virtrdf:DefaultQuadStorage</strong> only.
If a graph variable of a quad map pattern is not bound and no source graph specified by <strong>FROM</strong> clauses then quad maps for specific constant graphs are ignored.
In other words, if a default quad storage contains quad maps for specific graphs then the query in that storage should explicitly specify the graph in order to use a map for graph.
This rule will not work if the default quad map is removed from the <strong>virtrdf:DefaultQuadStorage</strong>.
This rule relates to the default storage itself, not to the containing patterns; copying some or all patterns into other storage will not reproduce there this special effect.
</p>
<p>So for example the query from below returns results when graph is specified i.e. 
when no graph is referenced, then run over physical store only is performed:</p>
<div>
      <pre class="programlisting">
SQL&gt;SPARQL 
SELECT * 
WHERE
    {
    &lt;http://localhost:8990/Demo/categories/CategoryID/1#this&gt;  ?p ?o 
  };
p        o
VARCHAR  VARCHAR
_______________________________________________________________________________

0 Rows. -- 0 msec.

SQL&gt;SPARQL 
SELECT * 
WHERE 
  { 
    GRAPH ?g 
      {
        &lt;http://localhost:8990/Demo/categories/CategoryID/1#this&gt;  ?p ?o 
      }
  };
g                              p                                                     o
VARCHAR                        VARCHAR                                               VARCHAR
___________________________________________________________________________________________________________________________________

http://localhost:8990/Demo#    http://www.w3.org/1999/02/22-rdf-syntax-ns#type       http://localhost:8990/schemas/Demo/Categories
http://localhost:8990/Demo#    http://localhost:8990/schemas/Demo/categoryid         1
http://localhost:8990/Demo#    http://localhost:8990/schemas/Demo/categoryname       ...
...

</pre>
    </div>
    <br />
<a name="rdfviewdescribingsourcerelationaltables" />
    <h3>14.5.6. Describing Source Relational Tables</h3>
<p>Quad map patterns of an application usually share a common set of source tables and quad map values of one pattern usually share either a single table or very small number of joined tables.
Join and filtering conditions are also usually repeated in different patterns.
It is not necessary to type table descriptions multiple times, they are declare once in the beginning of storage declaration statement and shared between all quad map declarations inside the statement.
Names of aliases can be used instead of table names in quad map values.
</p>
<div>
      <pre class="programlisting">
FROM DB.DBA.SYS_USERS as user WHERE (^{user.}^.U_IS_ROLE = 0)
FROM DB.DBA.SYS_USERS as group WHERE (^{group.}^.U_IS_ROLE = 1)
FROM DB.DBA.SYS_USERS as account
FROM user as active_user
  WHERE (^{active_user.}^.U_ACCOUNT_DISABLED = 0)
FROM DB.DBA.SYS_ROLE_GRANTS as grant
  WHERE (^{grant.}^.GI_SUPER = ^{account.}^.U_ID)
  WHERE (^{grant.}^.GI_SUB = ^{group.}^.U_ID)
  WHERE (^{grant.}^.GI_SUPER = ^{user.}^.U_ID)
</pre>
    </div>
<p>
This declares five distinct aliases for two distinct tables, and six filtering conditions.
Every condition is an SQL expression with placeholders where a reference to the table should be printed.
The SPARQL compiler will not try to parse texts of these expressions (except dummy search for placeholders), so any logical expressions are acceptable.
When a quad map pattern declaration refers to some aliases, the <strong>WHERE</strong> clause of the generated SQL code will contain a conjunction of all distinct texts of &quot;relevant&quot; conditions.
A condition is relevant if every alias inside the condition is used in some quad map value of the map pattern, either directly or via clause like <strong>from user as active_user</strong>.
(<strong>user</strong> is a &quot;<strong>base alias</strong>&quot; for <strong>active_user</strong>).
</p>
    <p>
Consider a group of four declarations.
</p>
<div>
      <pre class="programlisting">
graph &lt;http://myhost/sys&gt;
  {
    oplsioc:user_iri (active_user.U_ID)
        a oplsioc:active-user .
    oplsioc:membership_iri (grant.GI_SUPER, grant.GI_SUB).
        oplsioc:is_direct
            grant.GI_DIRECT ;
        oplsioc:member-e-mail
            active_user.U_E_MAIL
               where (^{active_user.}^.U_E_MAIL like &#39;mailto:%&#39;).
    ldap:account-ref (account.U_NAME)
        ldap:belongs-to
            ldap:account-ref (group.U_NAME) option (using grant).
  }
</pre>
    </div>
<p>
The first declaration will extend <strong>&lt;http://myhost/sys&gt;</strong> graph with one imaginary triples <strong>{ user a oplsioc:active-user }</strong> for every account record that is not a role and not disabled.
The second declaration deals with membership records.
A membership is a pair of a grantee (&quot;super&quot;) and a granted role (&quot;sub&quot;) stored as a row in <strong>DB.DBA.SYS_ROLE_GRANTS</strong>).
</p>
    <p>
The second declaration states that every membership has <strong>oplsioc:is_direct</strong> property with value from <strong>GI_DIRECT</strong> column of that table (roles may be granted to other roles and users, so permissions are &quot;direct&quot; or &quot;recursive&quot;).
</p>
    <p>
The third declaration declares <strong>oplsioc:member-e-mail</strong> property of memberships.
The value is a literal string from <strong>DB.DBA.SYS_USERS.U_E_MAIL</strong>, if the grantee is active (not disabled) and is not a role and its e-mail address starts with <strong>&#39;mailto:&#39;</strong>.
The join between <strong>DB.DBA.SYS_ROLE_GRANTS</strong> and <strong>DB.DBA.SYS_USERS</strong> is made by equality <strong>(GI_SUPER = U_ID)</strong> because the alias <strong>active_user</strong> in the declaration &quot;inherits&quot; all conditions specified for <strong>user</strong>.
In addition, the SPARQL compiler will add one more condition to check if the <strong>U_E_MAIL</strong> is not null because the NULL value is not a valid object and it knows that <strong>U_E_MAIL</strong> is not declared as <strong>NOT NULL</strong>.
</p>
    <p>
The last declaration contains an <strong>option</strong> clause.
As usual, this indicates that the basic functionality is good for many tasks but not for all.
In this declaration, the <strong>ldap:belongs-to</strong> property establishes a relation between grantee (subject) and a granted role (object).
Both subject and object IRIs are based on account name, <strong>DB.DBA.SYS_USERS.U_NAME</strong>, so the quad map pattern contains two references to different aliases of <strong>DB.DBA.SYS_USERS</strong> but no alias for <strong>DB.DBA.SYS_ROLE_GRANTS</strong>.
Hence the declaration could produce a triple for every row of the Cartesian product of the <strong>DB.DBA.SYS_USERS</strong>.
To fix the problem, <strong>option (using alias-name)</strong> tells the compiler to process the alias-name as if it&#39;s used in some quad map value of the pattern.
</p>
    <p>
It is an error to use an alias only in <strong>where</strong> clause of the quad map pattern but neither in values or in <strong>option (using alias-name)</strong>.
To detect more typos, an alias used in quad map values can not appear in <strong>option (using alias-name)</strong> clause.
</p>
<br />
<a name="rdfviewiriusingfunction" />
    <h3>14.5.7. Function-Based IRI Classes</h3>
<p>Most of IRI classes can be declared by a sprintf format string, but sophisticated cases may require calculations, not only printing the string. <strong>create IRI class using function</strong> allows the application transform relational values to IRIs by any custom routines.</p>
<p>
Let us extend the previous example about users and groups by a new class for grantees. Both users and groups are grantees and we have defined two IRI classes for them. Classes <strong>oplsioc:user_iri</strong> and <strong>oplsioc:group_iri</strong> work fine for quad maps of <strong>U_ID</strong> if and only if the value of <strong>U_IS_ROLE</strong> is accordingly restricted to FALSE or TRUE, otherwise one may occasionally generate, say, user IRI for a group.
To create and parse IRIs that correspond to any U_IDs, two functions should be created:
</p>
<div>
      <pre class="programlisting">
create function DB.DBA.GRANTEE_URI (in id integer)
returns varchar
{
  declare isrole integer;
  isrole := coalesce ((SELECT top 1 U_IS_ROLE
      FROM DB.DBA.SYS_USERS WHERE U_ID = id ) );
  if (isrole is null)
    return NULL;
  else if (isrole)
    return sprintf (&#39;http://%s/sys/group?id=%d&#39;, id);
  else
    return sprintf (&#39;http://%s/sys/user?id=%d&#39;, id);
};
</pre>
    </div>
<div>
      <pre class="programlisting">
create function DB.DBA.GRANTEE_URI_INVERSE (in id_iri varchar)
returns integer
{
  declare parts any;
  parts := sprintf_inverse (id_iri,
      &#39;http://myhost/sys/user?id=%d&#39;, 1 );
  if (parts is not null)
    {
      if (exists (SELECT top 1 1 FROM DB.DBA.SYS_USERS
          WHERE U_ID = parts[0] and not U_IS_ROLE ) )
        return parts[0];
    }
  parts := sprintf_inverse (id_iri,
      &#39;http://myhost/sys/group?id=%d&#39;, 1 );
  if (parts is not null)
    {
      if (exists (SELECT top 1 1 FROM DB.DBA.SYS_USERS
          WHERE U_ID = parts[0] and U_IS_ROLE ) )
        return parts[0];
   }
  return NULL;
  };
</pre>
    </div>
<p>These functions may be more useful if the SPARQL web service endpoint is allowed to use them:</p>
<div>
      <pre class="programlisting">
grant execute on DB.DBA.GRANTEE_URI to &quot;SPARQL&quot;;
grant execute on DB.DBA.GRANTEE_URI_INVERSE to &quot;SPARQL&quot;;
</pre>
    </div>
<p>
The next declaration creates an IRI class based on these two functions:
</p>
<div>
      <pre class="programlisting">
create iri class oplsioc:grantee_iri using
  function DB.DBA.GRANTEE_URI (in id integer)
    returns varchar,
  function DB.DBA.GRANTEE_URI_INVERSE (in id_iri varchar)
    returns integer .
</pre>
    </div>
<p>
In common case, IRI class declaration contains an N-array function that composes IRIs and N inverse functions that gets an IRI as an argument and extracts the Nth SQL value.
IRI composing function should silently return NULL on incorrect arguments instead of error signal.
Inverse functions should return NULL if the argument has an incorrect type or value.
</p>
<p>
It is possible to specify only composing function without any of inverse functions. However <strong>option (bijection)</strong> can not be used in that case, obviously.
</p>
<br />
<a name="rdfconnvarsiniriclasses" />
    <h3>14.5.8. Connection Variables in IRI Classes</h3>
<p>Writing function-based IRI class is overkill when the IRI can in principle be made by a <a href="fn_sprintf_iri.html">sprintf_iri</a> but the format should contain some context-specific data, such as host name used for the <a href="">dynamic renaming of local IRIs</a>.
Format strings offer a special syntax for that cases.
<strong>%{varname}U</strong> acts as <strong>%U</strong> but the function <a href="fn_sprintf.html">sprintf</a> will take the value from client connection variable <strong>varname</strong>, not from list of arguments.
Similarly, <a href="fn_sprintf_inverse.html">sprintf_inverse</a> will not return fragment that match to <strong>%{varname}U</strong> in the vector of other fragments; instead it will get the value from connection environment and ensure that it matches the fragment of input; mismatch between printed and actual value of variable will means that the whole string do not match the format.</p>
<p>SPARQL optimizer knows about this formatting feature and sometimes it makes more deductions from occurrence of <strong>%{varname}U</strong> than from occurrence of plain <strong>%U</strong>, so this notation may be used in <strong>option ( returns ...)</strong> when appropriate.
Of course, the optimizer has no access to the actual value of connection variable because it may vary from run to run or may change between the compilation and the run, but the value is supposed to be persistent during any single query run so <strong>%{myvariable}U</strong> in one place is equal to <strong>%{myvariable}U</strong> in other.</p>
<p>Connection variables are set by <a href="fn_connection_set.html">connection_set</a> and some of them have default values that are used if not overridden by application:</p>
<ul>
<li>
        <strong>URIQADefaultHost</strong> is for default host as it is specified in Virtuoso configuration file.
Note, however, that it will be escaped when printed so if it contains colon and port number then the colon is escaped.
In addition, there are special variables that match dynamic renaming of local IRIs more accurately.</li>
<li>
        <strong>WSHost</strong> is for host and port as it is used by current client connection for dynamic renaming.
The colon before port will be escaped.</li>
<li>
        <strong>WSHostName</strong> is for host name only, without port, as it is used by current client connection for dynamic renaming.</li>
<li>
        <strong>WSHostPort</strong> is for port part of host IRI. That is string, not integer. The only real use of the variable is in formats like <strong>http://%{WSHostName}U:%{WSHostPort}U/...</strong>.</li>
</ul>
<p>It is inconvenient to write different format strings for
different cases. Two most common policies are different host names
for default HTTP port of a publicly available service and different
non-default ports for one or more host names of an intranet
installation; these two approaches are almost never used in a mix. So
declaration of IRI classes may use shorthand
<strong>^{DynamicLocalFormat}^</strong> in format strings that is
expanded either to <strong>http://%{WSHost}U</strong> or to
<strong>http://%{WSHostName}U:%{WSHostPort}U/...</strong>,
depending on absence or presence of port number in the value of
<strong>DefaultHost</strong> parameter of
<strong>URIQA</strong> section of configuration file.</p>
<div class="note">
      <div class="notetitle">Note:</div>
      <p>
        <strong>^{DynamicLocalFormat}^</strong> is for IRI class declarations only and is not expanded in any other place, so it is useful sometimes to create an IRI class with empty argument list in order to get &quot;almost constant&quot; IRIs calculated without writing special procedures.</p>
    </div>
<br />
<a name="rdfviewbijandreturns" />
    <h3>14.5.9. Lookup Optimization -- BIJECTION and RETURNS Options</h3>
<p>
There is one subtle problem with IRI class declarations.
To get benefit from a relational index, SPARQL optimizer should compose equality between table column and some known SQL value, not between return value of IRI class and a known composed IRI.
In addition, redundant calculations of IRIs takes time.
To enable this optimization, an IRI class declaration should end with <strong>option (bijection)</strong> clause. For some simple format strings the compiler may recognize the bijection automatically but an explicit declaration is always a good idea.
</p>
<div class="note">
      <div class="notetitle">Note:</div>
<p>
See also: <a href="http://en.wikipedia.org/wiki/One-to-one_correspondence">Wikipedia - Bijection</a>.
In mathematics, a bijection, or a bijective function is a function f from a set X to a set Y such that,
for every y in Y, there is exactly one x in X such that f(x) = y.
</p>
<p>
Alternatively, f is bijective if it is a one-to-one correspondence between those sets; i.e.,
both one-to-one (injective) and onto (surjective).
</p>
</div>
<p>
The SPARQL compiler may produce big amounts of SQL code when the query contains equality of two calculated IRIs and these IRIs may come from many different IRI classes.
It is possible to provide hints that will let the compiler check if two IRI classes form disjoint sets of possible IRI values. The more disjoint sets are found the less possible combinations remain so the resulting SQL query will contain fewer unions of joins.
The SPARQL compiler can prove some properties of sprintf format strings. E.g., it can prove that set of all strings printed by &quot;http://example.com/item%d&quot; and the set of strings printed by &quot;http://example.com/item%d/&quot; are disjoint.
It can prove some more complicated statements about unions and intersections of sets of strings.
The IRI or literal class declaration may contain <strong>option (returns ...)</strong> clause that will specify one or more sprintf patterns that cover the set of generated values.
Consider a better version of IRI class declaration listed above:
</p>
<div>
      <pre class="programlisting">
create iri class oplsioc:grantee_iri using
  function DB.DBA.GRANTEE_URI (in id integer)
    returns varchar,
  function DB.DBA.GRANTEE_URI_INVERSE (in id_iri varchar)
    returns integer
  option ( bijection,
    returns &quot;http://myhost/sys/group?id=%d&quot;
    union   &quot;http://myhost/sys/user?id=%d&quot; ) .
</pre>
    </div>
<p>
It is very important to keep IRI classes easily distinguishable by the text of IRI string and easy to parse.
</p>
<ul>
<li>Format <strong>%U</strong> is better than <strong>%s</strong>, especially in the middle of IRI, because the <strong>%U</strong> fragment can not contain characters like &quot;/&quot; or &quot;=&quot;; one may prove that <strong>/%U/</strong> and <strong>/abra%d/cadabra/</strong> are disjoint but <strong>/%s/</strong> and <strong>/abra%d/cadabra/</strong> are not disjoint.
</li>
      <li>It is better when the variable part like <strong>%U</strong> or <strong>%d</strong> is placed between characters that may not occur in the <strong>%U</strong> or <strong>%d</strong> output, i.e. <strong>%U</strong> is placed between &quot;/&quot;, &quot;&amp;&quot; or &quot;=&quot; and <strong>%d</strong> is placed between non-digits; <strong>order_line_%d</strong> is better than <strong>order-line-%d</strong> because minus may be part of <strong>%d</strong> output.
</li>
      <li>End-of-line is treated as a special character, so placing <strong>%U</strong> or <strong>%d</strong> between &quot;/&quot; and end of line is as good as placing it between two &quot;/&quot;.
</li>
    </ul>
<p>
In some cases <strong>option (returns ...)</strong> can be used for IRI classes that are declared using sprintf format, but actual data have more specific format.
Consider a literal class declaration that is used to output strings and the application knows that all these strings are ISBN numbers:
</p>
<div>
      <pre class="programlisting">
create literal class example:isbn_ref &quot;%s&quot; (in isbn varchar not null)
  option ( bijection, returns &quot;%u-%u-%u-%u&quot; union &quot;%u-%u-%u-X&quot; )
</pre>
    </div>
<p>
Sometimes interoperability restrictions will force you to violate these rules but please try to follow them as often as possible.
</p>
<br />
<a name="rdfviewsubclasses" />
    <h3>14.5.10. Join Optimization -- Declaring IRI Subclasses</h3>
<p>
Additional problem appears when the equality is between two IRIs of two different IRI classes.
Even if both of them are bijections, the compiler does not know if these IRI classes behave identically on the intersection of their domains.
To let the optimizer know this fact, one IRI class can be explicitly declared as a subclass of another:
</p>
<div>
      <pre class="programlisting">
make oplsioc:user_iri subclass of oplsioc:grantee_iri .
make oplsioc:group_iri subclass of oplsioc:grantee_iri .
</pre>
    </div>
<p>
The SPARQL compiler can not check the validity of a subclass declaration.
The developer should carefully test functions to ensure that transformations are really subclasses, as well as to ensure that functions of an IRI class declarations are really inverse to each other.
</p>
    <p>
When declaring that a table&#39;s primary key is converted into a IRI according to one IRI class, one usually declares that all foreign keys referring to this class also get converted into an IRI as per this same class, or subclass of same class.
</p>
    <p>
Subclasses can be declared for literal classes as well as for IRI classes, but this case is rare. The reason is that most of literals are made by identity literal classes that are disjoint to each other even if values may be equal in SQL sense, such as <strong>&quot;2&quot;</strong> of type <strong>xsd:integer</strong> and <strong>&quot;2.0&quot;</strong> of type <strong>xsd:double</strong>.
</p>
    <br />
<a name="rdfmetadatarecovery" />
    <h3>14.5.11. RDF Metadata Maintenance and Recovery</h3>
   <p>
This section refers to checking and backing up RDF view and storage declarations only. The checks and backup/restore do not affect physical quads, relational schema or tables or data therein. For general backup and restore, see server administration.
     To detect and fix automatically most popular sorts of RDF metadata corruption use <a href="fn_rdf_audit_metadata.html">DB.DBA.RDF_AUDIT_METADATA</a>.
It is also possible to backup RDF data by
    <a href="fn_rdf_backup_metadata.html">DB.DBA.RDF_BACKUP_METADATA</a>
and restore the saved state later by using
    <a href="fn_rdf_restore_metadata.html">DB.DBA.RDF_RESTORE_METADATA</a>.
It is convenient to make a backup before any modification of quad storages, quad map patterns or IRI classes, especially during debugging new RDF Views.
   </p>
<div class="note">
      <div class="notetitle">Note:</div>
      <p>In SQL, adding a new view can not break anything. This is because SQL lacks the ability of querying &quot;everything&quot; so data sources are always specified. This is not true for SPARQL, so please treat <strong>any</strong> metadata manipulation as potentially destructive operation. If an RDF storage is supposed to be used by more than one application then these applications should be tested together, not one after other, and they should be installed/upgraded on live database in the very same order as they were installed/upgraded on instrumental machine during testing. Always remember that these applications share RDF tables so they may interfere.</p>
    </div>
<br />
<a name="splitrdfview" />
    <h3>14.5.12. Split RDF View</h3>
<p>RDF View can be created by two or more &quot;sparql alter storage&quot; statements. In each statement
can be created one quad map that contains mappings for half or a third of all tables. Quad maps
created should have distinct names but may mention same graph. The important fact is that if the
RDF View in question is exclusive for a graph then only the last quad map should be exclusive but
all previous should not have this option. This is because if a map is exclusive on a graph the rest
of maps on that graph will be silently ignored.</p>
<p>The example below shows a sample part of the Virtuoso eCRM Views code,
where the RDF view is split in two parts: with quad map virtrdf:ecrmDemo1 and with
quad map virtrdf:ecrmDemo2:</p>
<div>
      <pre class="programlisting">
SPARQL
prefix ecrm: &lt;http://demo.openlinksw.com/schemas/ecrm#&gt;
prefix oplsioc: &lt;http://www.openlinksw.com/schemas/oplsioc#&gt;
prefix sioc: &lt;http://rdfs.org/sioc/ns#&gt;
prefix foaf: &lt;http://xmlns.com/foaf/0.1/&gt;
prefix cal: &lt;http://www.w3.org/2002/12/cal/ical#&gt;
prefix geo: &lt;http://www.w3.org/2003/01/geo/wgs84_pos#&gt;
prefix product: &lt;http://www.swop-project.eu/ontologies/pmo/product.owl#&gt;
prefix owl: &lt;http://www.w3.org/2002/07/owl#&gt;
drop quad map virtrdf:ecrmDemo1 .
;

SPARQL
prefix ecrm: &lt;http://demo.openlinksw.com/schemas/ecrm#&gt;
prefix oplsioc: &lt;http://www.openlinksw.com/schemas/oplsioc#&gt;
prefix sioc: &lt;http://rdfs.org/sioc/ns#&gt;
prefix foaf: &lt;http://xmlns.com/foaf/0.1/&gt;
prefix cal: &lt;http://www.w3.org/2002/12/cal/ical#&gt;
prefix geo: &lt;http://www.w3.org/2003/01/geo/wgs84_pos#&gt;
prefix product: &lt;http://www.swop-project.eu/ontologies/pmo/product.owl#&gt;
prefix owl: &lt;http://www.w3.org/2002/07/owl#&gt;
drop quad map virtrdf:ecrmDemo2 .
;

...

SPARQL
prefix ecrm: &lt;http://demo.openlinksw.com/schemas/ecrm#&gt;
prefix oplsioc: &lt;http://www.openlinksw.com/schemas/oplsioc#&gt;
prefix sioc: &lt;http://rdfs.org/sioc/ns#&gt;
prefix foaf: &lt;http://xmlns.com/foaf/0.1/&gt;
prefix cal: &lt;http://www.w3.org/2002/12/cal/ical#&gt;
prefix geo: &lt;http://www.w3.org/2003/01/geo/wgs84_pos#&gt;
prefix product: &lt;http://www.swop-project.eu/ontologies/pmo/product.owl#&gt;
prefix owl: &lt;http://www.w3.org/2002/07/owl#&gt;
alter quad storage virtrdf:DefaultQuadStorage
FROM eCRM.DBA.SFA_SALES_QUOTA_VIEW2 as sales_quotas
FROM eCRM.DBA.SFA_COMPANIES_VIEW2 as companies
FROM eCRM.DBA.SFA_COMPANIES as companies_table text literal companies_table.DESCRIPTION of (companies.DESCRIPTION)
FROM eCRM.DBA.SFA_CONTACTS_VIEW2 as contacts
FROM eCRM.DBA.SFA_CONTACTS as contacts_table text literal contacts_table.NAME_FIRST of (contacts.NAME_FIRST)
FROM eCRM.DBA.SFA_EMPLOYMENTS_VIEW2 as employments
FROM eCRM.DBA.SFA_LEADS_VIEW2 as leads
FROM eCRM.DBA.SFA_LEADS as leads_table text literal leads_table.SUBJECT of (leads.SUBJECT)
FROM eCRM.DBA.SFA_OPPORTUNITIES_VIEW2 as opportunities
FROM eCRM.DBA.SFA_OPPORTUNITIES as opportunities_table text literal opportunities_table.OPPORTUNITY_NAME of (opportunities.OPPORTUNITY_NAME)
FROM eCRM.DBA.SFA_ACTIVITIES as activities
FROM eCRM.DBA.SFA_MAIL_MESSAGES as messages
FROM eCRM.DBA.SFA_DOCUMENTS_VIEW2 as documents
FROM eCRM.DBA.SFA_INFLUENCERS_VIEW2 as influencers
FROM eCRM.DBA.SFA_TEAMS_VIEW2 as teams
FROM eCRM.DBA.SFA_NOTES_VIEW2 as notes
FROM eCRM.DBA.SFA_NOTES as notes_table text literal notes_table.DESCRIPTION of (notes.DESCRIPTION)
FROM eCRM.DBA.SFA_COMPETITORS_VIEW2 as competitors
FROM eCRM.DBA.SFA_ISSUES_VIEW2 as issues
FROM eCRM.DBA.SFA_CUSTOM_FIELD_DEFS_VIEW2 as custom_field_defs
FROM eCRM.DBA.SFA_CUSTOM_FIELDS_VIEW2 as custom_fields
FROM eCRM.DBA.SFA_CASES_VIEW2 as cases
FROM eCRM.DBA.SFA_CASES as cases_table text literal cases_table.SUMMARY of (cases.SUMMARY)
FROM eCRM.DBA.SFA_ORDERS_VIEW2 as orders
FROM eCRM.DBA.SFA_ORDERS as orders_table text literal orders_table.EMAIL of (orders.EMAIL)
FROM eCRM.DBA.SFA_ORDER_ITEMS_VIEW2 as order_items
FROM eCRM.DBA.PM_CATEGORIES_VIEW2 as categories
FROM eCRM.DBA.PM_PRODUCT_ATTRIBUTE_DEFS_VIEW2 as product_attribute_defs
FROM eCRM.DBA.PM_PRODUCTS_VIEW2 as products
FROM eCRM.DBA.PM_PRODUCTS as products_table text literal products_table.DESCRIPTION of (products.DESCRIPTION)
FROM eCRM.DBA.PM_PRODUCT_ATTRIBUTES_VIEW2 as product_attributes
FROM eCRM.DBA.PM_CATALOGS_VIEW2 as catalogs
FROM eCRM.DBA.PM_CATALOG_PRODUCTS_VIEW2 as catalog_products
FROM eCRM.DBA.XSYS_MODULES as modules
FROM eCRM.DBA.XSYS_REGISTRY as registries
FROM eCRM.DBA.XSYS_ORGANIZATIONS_DATA as organizations_data
FROM eCRM.DBA.XSYS_MESSAGES as xsysmessages
FROM eCRM.DBA.XSYS_COUNTRIES_VIEW2 as countries
FROM eCRM.DBA.XSYS_PROVINCES_VIEW2 as provinces
FROM eCRM.DBA.XSYS_TIMEZONES as timezones
FROM eCRM.DBA.XSYS_MIME_TYPES as mimetypes
FROM eCRM.DBA.XSYS_MIME_EXTENSIONS as mimeexts
FROM eCRM.DBA.XSYS_CNAMES as cnames
FROM eCRM.DBA.XSYS_QUOTAS as quotas
FROM eCRM.DBA.XSYS_ROLES as roles
FROM eCRM.DBA.XSYS_ACCOUNTS as accounts
FROM eCRM.DBA.XSYS_USERDATA as userdatas
FROM eCRM.DBA.XSYS_GROUPDATA as groupdatas
FROM eCRM.DBA.XSYS_MEMBERS as members
FROM eCRM.DBA.XSYS_SESSIONS_DATA as sessionsdatas
FROM eCRM.DBA.XSYS_SESSION_DATA as sessiondatas
FROM eCRM.DBA.XSYS_LIST_MEMBERS_DEFS as list_members_defs
FROM eCRM.DBA.XSYS_CLASSES as classes
FROM eCRM.DBA.XSYS_ORG_CLASSES as org_classes
FROM eCRM.DBA.XSYS_CLASS_METHODS as class_methods
FROM eCRM.DBA.XSYS_CLASS_VIEWS as class_views
FROM eCRM.DBA.XSYS_ROLE_PRIVILEGES as role_priveleges
FROM eCRM.DBA.XSYS_USER_PRIVILEGES as user_priveleges
FROM eCRM.DBA.XSYS_HISTORY as history
FROM eCRM.DBA.XSYS_USERS as xsys_users
FROM eCRM.DBA.AP_PROCESSES_VIEW2 as ap_processes
FROM eCRM.DBA.AP_RULES_VIEW2 as ap_rules
FROM eCRM.DBA.AP_QUEUE as ap_queues
WHERE (^{companies.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{contacts.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{leads.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{products.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{orders.}^.SHIP_COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{leads_table.}^.FREETEXT_ID = ^{leads.}^.FREETEXT_ID)
WHERE (^{contacts_table.}^.FREETEXT_ID = ^{contacts.}^.FREETEXT_ID)
WHERE (^{companies_table.}^.FREETEXT_ID = ^{companies.}^.FREETEXT_ID)
WHERE (^{opportunities_table.}^.FREETEXT_ID = ^{opportunities.}^.FREETEXT_ID)
WHERE (^{cases_table.}^.FREETEXT_ID = ^{cases.}^.FREETEXT_ID)
WHERE (^{notes_table.}^.FREETEXT_ID = ^{notes.}^.FREETEXT_ID)
WHERE (^{orders_table.}^.FREETEXT_ID = ^{orders.}^.FREETEXT_ID)
WHERE (^{products_table.}^.FREETEXT_ID = ^{products.}^.FREETEXT_ID)
    {
        create virtrdf:ecrmDemo1 as graph iri (&quot;http://^{URIQADefaultHost}^/ecrm&quot;) option (order 1501)
      {
            ecrm:Country (countries.COUNTRY_NAME)
                a ecrm:Country
                    as virtrdf:Country-Countrys2 ;
                a geo:SpatialThing
                    as virtrdf:Country-Countrys ;
                owl:sameAs ecrm:dbpedia_iri (countries.COUNTRY_NAME) ;
                ecrm:countryID countries.COUNTRY_ID
                        as virtrdf:Country-COUNTRY_ID ;
                ecrm:countryID3 countries.COUNTRY_ID3
                        as virtrdf:Country-COUNTRY_ID3 ;
                ecrm:isoCode countries.ISO_CODE
                        as virtrdf:Country-ISO_CODE ;
                ecrm:countryName countries.COUNTRY_NAME
                        as virtrdf:Country-COUNTRY_NAME .

            ecrm:Country (countries.COUNTRY_NAME)
                        ecrm:has_province
            ecrm:Province (provinces.COUNTRY_ID, provinces.PROVINCE_NAME) where
                        (^{provinces.}^.COUNTRY_ID = ^{countries.}^.COUNTRY_ID) as virtrdf:ecrmCountry-has_province .

...
  } .
} .
;
SPARQL
prefix ecrm: &lt;http://demo.openlinksw.com/schemas/ecrm#&gt;
prefix oplsioc: &lt;http://www.openlinksw.com/schemas/oplsioc#&gt;
prefix sioc: &lt;http://rdfs.org/sioc/ns#&gt;
prefix foaf: &lt;http://xmlns.com/foaf/0.1/&gt;
prefix geo: &lt;http://www.w3.org/2003/01/geo/wgs84_pos#&gt;
prefix cal: &lt;http://www.w3.org/2002/12/cal/ical#&gt;
prefix product: &lt;http://www.swop-project.eu/ontologies/pmo/product.owl#&gt;
prefix owl: &lt;http://www.w3.org/2002/07/owl#&gt;
alter quad storage virtrdf:DefaultQuadStorage
FROM eCRM.DBA.SFA_SALES_QUOTA_VIEW2 as sales_quotas
FROM eCRM.DBA.SFA_COMPANIES_VIEW2 as companies
FROM eCRM.DBA.SFA_COMPANIES as companies_table text literal companies_table.DESCRIPTION of (companies.DESCRIPTION)
FROM eCRM.DBA.SFA_CONTACTS_VIEW2 as contacts
FROM eCRM.DBA.SFA_CONTACTS as contacts_table text literal contacts_table.NAME_FIRST of (contacts.NAME_FIRST)
FROM eCRM.DBA.SFA_EMPLOYMENTS_VIEW2 as employments
FROM eCRM.DBA.SFA_LEADS_VIEW2 as leads
FROM eCRM.DBA.SFA_LEADS as leads_table text literal leads_table.SUBJECT of (leads.SUBJECT)
FROM eCRM.DBA.SFA_OPPORTUNITIES_VIEW2 as opportunities
FROM eCRM.DBA.SFA_OPPORTUNITIES as opportunities_table text literal opportunities_table.OPPORTUNITY_NAME of (opportunities.OPPORTUNITY_NAME)
FROM eCRM.DBA.SFA_ACTIVITIES as activities
FROM eCRM.DBA.SFA_MAIL_MESSAGES as messages
FROM eCRM.DBA.SFA_DOCUMENTS_VIEW2 as documents
FROM eCRM.DBA.SFA_INFLUENCERS_VIEW2 as influencers
FROM eCRM.DBA.SFA_TEAMS_VIEW2 as teams
FROM eCRM.DBA.SFA_NOTES_VIEW2 as notes
FROM eCRM.DBA.SFA_NOTES as notes_table text literal notes_table.DESCRIPTION of (notes.DESCRIPTION)
FROM eCRM.DBA.SFA_COMPETITORS_VIEW2 as competitors
FROM eCRM.DBA.SFA_ISSUES_VIEW2 as issues
FROM eCRM.DBA.SFA_CUSTOM_FIELD_DEFS_VIEW2 as custom_field_defs
FROM eCRM.DBA.SFA_CUSTOM_FIELDS_VIEW2 as custom_fields
FROM eCRM.DBA.SFA_CASES_VIEW2 as cases
FROM eCRM.DBA.SFA_CASES as cases_table text literal cases_table.SUMMARY of (cases.SUMMARY)
FROM eCRM.DBA.SFA_ORDERS_VIEW2 as orders
FROM eCRM.DBA.SFA_ORDERS as orders_table text literal orders_table.EMAIL of (orders.EMAIL)
FROM eCRM.DBA.SFA_ORDER_ITEMS_VIEW2 as order_items
FROM eCRM.DBA.PM_CATEGORIES_VIEW2 as categories
FROM eCRM.DBA.PM_PRODUCT_ATTRIBUTE_DEFS_VIEW2 as product_attribute_defs
FROM eCRM.DBA.PM_PRODUCTS_VIEW2 as products
FROM eCRM.DBA.PM_PRODUCTS as products_table text literal products_table.DESCRIPTION of (products.DESCRIPTION)
FROM eCRM.DBA.PM_PRODUCT_ATTRIBUTES_VIEW2 as product_attributes
FROM eCRM.DBA.PM_CATALOGS_VIEW2 as catalogs
FROM eCRM.DBA.PM_CATALOG_PRODUCTS_VIEW2 as catalog_products
FROM eCRM.DBA.XSYS_MODULES as modules
FROM eCRM.DBA.XSYS_REGISTRY as registries
FROM eCRM.DBA.XSYS_ORGANIZATIONS_DATA as organizations_data
FROM eCRM.DBA.XSYS_MESSAGES as xsysmessages
FROM eCRM.DBA.XSYS_COUNTRIES_VIEW2 as countries
FROM eCRM.DBA.XSYS_PROVINCES_VIEW2 as provinces
FROM eCRM.DBA.XSYS_TIMEZONES as timezones
FROM eCRM.DBA.XSYS_MIME_TYPES as mimetypes
FROM eCRM.DBA.XSYS_MIME_EXTENSIONS as mimeexts
FROM eCRM.DBA.XSYS_CNAMES as cnames
FROM eCRM.DBA.XSYS_QUOTAS as quotas
FROM eCRM.DBA.XSYS_ROLES as roles
FROM eCRM.DBA.XSYS_ACCOUNTS as accounts
FROM eCRM.DBA.XSYS_USERDATA as userdatas
FROM eCRM.DBA.XSYS_GROUPDATA as groupdatas
FROM eCRM.DBA.XSYS_MEMBERS as members
FROM eCRM.DBA.XSYS_SESSIONS_DATA as sessionsdatas
FROM eCRM.DBA.XSYS_SESSION_DATA as sessiondatas
FROM eCRM.DBA.XSYS_LIST_MEMBERS_DEFS as list_members_defs
FROM eCRM.DBA.XSYS_CLASSES as classes
FROM eCRM.DBA.XSYS_ORG_CLASSES as org_classes
FROM eCRM.DBA.XSYS_CLASS_METHODS as class_methods
FROM eCRM.DBA.XSYS_CLASS_VIEWS as class_views
FROM eCRM.DBA.XSYS_ROLE_PRIVILEGES as role_priveleges
FROM eCRM.DBA.XSYS_USER_PRIVILEGES as user_priveleges
FROM eCRM.DBA.XSYS_HISTORY as history
FROM eCRM.DBA.XSYS_USERS as xsys_users
FROM eCRM.DBA.AP_PROCESSES_VIEW2 as ap_processes
FROM eCRM.DBA.AP_RULES_VIEW2 as ap_rules
FROM eCRM.DBA.AP_QUEUE as ap_queues
WHERE (^{companies.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{contacts.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{leads.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{products.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{orders.}^.SHIP_COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{leads_table.}^.FREETEXT_ID = ^{leads.}^.FREETEXT_ID)
WHERE (^{contacts_table.}^.FREETEXT_ID = ^{contacts.}^.FREETEXT_ID)
WHERE (^{companies_table.}^.FREETEXT_ID = ^{companies.}^.FREETEXT_ID)
WHERE (^{opportunities_table.}^.FREETEXT_ID = ^{opportunities.}^.FREETEXT_ID)
WHERE (^{cases_table.}^.FREETEXT_ID = ^{cases.}^.FREETEXT_ID)
WHERE (^{notes_table.}^.FREETEXT_ID = ^{notes.}^.FREETEXT_ID)
WHERE (^{orders_table.}^.FREETEXT_ID = ^{orders.}^.FREETEXT_ID)
WHERE (^{products_table.}^.FREETEXT_ID = ^{products.}^.FREETEXT_ID)
{
        create virtrdf:ecrmDemo2 as graph iri (&quot;http://^{URIQADefaultHost}^/ecrm&quot;) option (exclusive, order 1502)
  {
            ecrm:Order (orders.ORG_ID, orders.ORDER_ID)
                a ecrm:Order
                    as virtrdf:Order-Orders ;
                ecrm:has_ecrm_organization ecrm:OrganizationsData(orders.ORG_ID, organizations_data.DNS_ZONE) where (^{orders.}^.ORG_ID = ^{organizations_data.}^.ORG_ID)
                        as virtrdf:Order-ORG_ID ;
                ecrm:owner ecrm:XSys_User(orders.ORG_ID, xsys_users.ACCOUNT_NAME, orders.OWNER_ID)
                        where (^{orders.}^.OWNER_ID = ^{xsys_users.}^.ACCOUNT_ID and ^{orders.}^.ORG_ID = ^{xsys_users.}^.ORG_ID)
                        as virtrdf:Order-OWNER_ID ;
                ecrm:FREETEXT_ID orders.FREETEXT_ID
                        as virtrdf:Order-FREETEXT_ID ;
                ecrm:has_company ecrm:Company(orders.COMPANY_NAME, orders.COMPANY_ID, orders.ORG_ID)
                        as virtrdf:Order-COMPANY_ID ;
                ecrm:companyName orders.COMPANY_NAME
                        as virtrdf:Order-COMPANY_NAME ;
                ecrm:has_contact ecrm:Contact(contacts.NAME_FIRST, contacts.NAME_MIDDLE, contacts.NAME_LAST, orders.CONTACT_ID, orders.ORG_ID)
                        where (^{orders.}^.CONTACT_ID = ^{contacts.}^.CONTACT_ID and ^{orders.}^.ORG_ID = ^{contacts.}^.ORG_ID)
                        as virtrdf:Order-CONTACT_ID ;
                ecrm:contactName orders.CONTACT_NAME
                        as virtrdf:Order-CONTACT_NAME ;
                ecrm:orderNo orders.ORDER_NO
                        as virtrdf:Order-ORDER_NO ;
                ecrm:shipFirstName orders.SHIP_FNAME
                        as virtrdf:Order-SHIP_FNAME ;
                ecrm:shipSecondName orders.SHIP_SNAME
                        as virtrdf:Order-SHIP_SNAME ;
                ecrm:phoneNumber orders.PHONE_NUMBER
                        as virtrdf:Order-PHONE_NUMBER ;
                ecrm:phoneExtension orders.PHONE_EXTENSION
                        as virtrdf:Order-PHONE_EXTENSION ;
                ecrm:email orders.EMAIL
                        as virtrdf:Order-EMAIL ;
                ecrm:shipCountry ecrm:Country(orders.SHIP_COUNTRY_NAME)
                        as virtrdf:Order-SHIP_COUNTRY_NAME ;
                ecrm:shipCountryCode ecrm:Country (countries.COUNTRY_NAME) where  (^{countries.}^.COUNTRY_NAME = ^{orders.}^.SHIP_COUNTRY_NAME)
                        as virtrdf:Order-SHIP_COUNTRY_CODE ;
                ecrm:shipProvince orders.SHIP_PROVINCE
                        as virtrdf:Order-SHIP_PROVINCE ;
                ecrm:shipCity orders.SHIP_CITY
                        as virtrdf:Order-SHIP_CITY ;
                ecrm:dbpedia_shipCity ecrm:dbpedia_iri (orders.SHIP_CITY)
                        as virtrdf:Order-SHIP_dbpedia_CITY ;
                ecrm:shipPostalCode orders.SHIP_POSTAL_CODE
                        as virtrdf:Order-SHIP_POSTAL_CODE ;
                ecrm:shipAddress1 orders.SHIP_ADDRESS1
                        as virtrdf:Order-SHIP_ADDRESS1 ;
                ecrm:shipAddress2 orders.SHIP_ADDRESS2
                        as virtrdf:Order-SHIP_ADDRESS2 ;
                ecrm:salesRep orders.SALESREP
                        as virtrdf:Order-SALESREP ;
                ecrm:orderDate orders.ORDER_DATE
                        as virtrdf:Order-ORDER_DATE ;
                ecrm:orderValue orders.ORDER_VALUE
                        as virtrdf:Order-ORDER_VALUE ;
                ecrm:refund orders.REFUND
                        as virtrdf:Order-REFUND ;
                ecrm:year orders.YEAR
                        as virtrdf:Order-YEAR ;
                ecrm:month orders.MONTH
                        as virtrdf:Order-MONTH ;
                ecrm:quarter orders.QUARTER
                        as virtrdf:Order-QUARTER ;
                ecrm:financialYear orders.FINANCIAL_YEAR
                        as virtrdf:Order-FINANCIAL_YEAR ;
                ecrm:CONTACT_REL_ID orders.CONTACT_REL_ID
                        as virtrdf:Order-CONTACT_REL_ID ;
                ecrm:COMPANY_REL_ID orders.COMPANY_REL_ID
                        as virtrdf:Order-COMPANY_REL_ID .

...
        } .
} .
;

</pre>
    </div>
<br />
<a name="rdfviewsrcur" />
    <h3>14.5.13. RDF views and recursive FK relationships</h3>
  <p>Here is sample example of a script to include an additional table alias for a table:</p>
<div>
      <pre class="programlisting">
alter quad storage virtrdf:DefaultQuadStorage
  :
  FROM isports_rdf.prs10_isports_rdf.VRef_Call      as Ref_Call_tbl
  FROM isports_rdf.prs10_isports_rdf.VRef_Call      as Ref_Call_tbl_1
  :
{
  :
  refcall:ref-call_iri (Ref_Call_tbl.Call_Num) a refcall:Ref-Call as
virtrdf:ref-call_pk ;
  :
  refcall:has_parent  refcall:ref-call_iri (Ref_Call_tbl_1.Call_Num)
where  ( ^{Ref_Call_tbl.}^.Parent    = ^{Ref_Call_tbl_1.}^.Call_Num )   as
virtrdf:Ref-Call_has_parent .
</pre>
    </div>
  <p>This demonstrates the way to self-join the table VRef_Call with itself. Like in SQL,
are needed two different aliases for one table if you want to join it with itself.
  </p>
    <br />
<table border="0" width="90%" id="navbarbottom">
    <tr>
        <td align="left" width="33%">
          <a href="rdfgraphsecurity.html" title="RDF Graphs Security">Previous</a>
          <br />RDF Graphs Security</td>
     <td align="center" width="34%">
          <a href="rdfandsparql.html">Chapter Contents</a>
     </td>
        <td align="right" width="33%">
          <a href="rdfrdfviewgnr.html" title="Automated Generation of RDF Views over Relational Data Sources">Next</a>
          <br />Automated Generation of RDF Views over Relational Data Sources</td>
    </tr>
    </table>
  </div>
  <div id="footer">
    <div>Copyright© 1999 - 2009 OpenLink Software All rights reserved.</div>
   <div id="validation">
    <a href="http://validator.w3.org/check/referer">
        <img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" />
    </a>
    <a href="http://jigsaw.w3.org/css-validator/">
        <img src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!" height="31" width="88" />
    </a>
   </div>
  </div>
 </body>
</html>