[
Table Of Contents
| Keyword Index
]
relation(n) 0.8.5 ral "Relation Operators"
relation - Operators for Relation Values
TABLE OF CONTENTS
SYNOPSIS
DESCRIPTION
STRING REPRESENTATION
EXAMPLE
COMMANDS
SEE ALSO
KEYWORDS
COPYRIGHT
package require ral ?0.8.5?
This manpage describes the relation command.
The relation
command is part of the Tcl Relational Algebra Library (ral) package.
The relation command defines a set of operators on relations that
constitute the formal algebra of relations that is supported by TclRAL.
The algebra is patterned after that described by Date (Date, C.J.,
An Introduction to Database Systems, 8th ed, Pearson Education, 2004,
ISBN 0-321-19784-4, chap. 7)
Formally a relation has a heading and a body.
The heading, like a tuple heading, defines the attribute names and
data types of the components of the relation.
The body consists of tuples, all of which match the heading.
A relation also has one or more identifiers (also known as candidate keys).
Each identifier consists of one or more attributes of the relation and
every tuple in the body of the relation will be unique in all their values
with respect to all the identifiers.
Because relations are fundamentally sets, several things should be noted:
-
There is no left to right ordering of the attributes.
Like tuples, relations have no real left to right ordering.
The implementation may choose to store attributes in any order
and users should not depend upon certain string representations
nor operate on relations with any operators other than those given here.
-
There is no top to bottom ordering of tuples.
Again the implementation is free to store tuples in any order it chooses.
There are no indexing operations that depend upon a tuple at some fixed
location.
-
There are no duplicate tuples and there is no concept of a NULL value.
Relations are sets and sets do not have duplicates.
All attributes of all tuples of a relation must contain a valid value of
the data type defined for that attribute.
Note that all the operators are read only in the sense that
they operate on relation values without modifying them.
All of these operators return either a new relation or scalar value and
do not modify the relation arguments.
Only the relvar command can modify a relation variable in place.
Like any Tcl value, relations have a string representation.
The string representation of a relations is a specially formatted list
consisting of four elements:
-
The keyword Relation.
-
The relation heading.
-
The identifiers of the relation.
-
The relation body.
The relation heading is a list containing an even number of elements
consisting of alternating
attribute names and attribute data types.
It is the same form as a tuple heading.
The identifiers (a.k.a. candidate keys) of a relation are specified as a list.
Each identifer list element is in turn a list containing the attribute
names that constitute the identifier.
Every relation must have at least one identifier.
The body of a relation consists of a list of tuples.
Each tuple in the body is in a list containing an even number of elements
consisting alternately of an
attribute name and an attribute value.
The following is a literal string representation of a relation with
one tuple in its body.
|
{Relation {DogName string Breed string} DogName {{DogName Fido Breed Poodle}}}
|
In the command descriptions that follow,
we will often refer to the example data given below.
We assume that the relation is contained in a Tcl variable with the
same name as the tables given below.
For brevity we assume that the necessary commands have been imported into
the namespace of the example.
|
% set DOG {
Relation
{DogName string Breed string}
DogName
{
{DogName Fido Breed Poodle}
{DogName Sam Breed Collie}
{DogName Spot Breed Terrier}
{DogName Rover Breed Retriever}
{DogName Fred Breed Spaniel}
{DogName Jumper Breed Mutt}
}
}
% relformat $DOG DOG
+=======+---------+
|DogName|Breed |
|string |string |
+=======+---------+
|Fido |Poodle |
|Sam |Collie |
|Spot |Terrier |
|Rover |Retriever|
|Fred |Spaniel |
|Jumper |Mutt |
+=======+---------+
DOG
---
% set OWNER {
Relation
{OwnerName string Age int City string}
OwnerName
{
{OwnerName Sue Age 24 City Cupertino}
{OwnerName George Age 35 City Sunnyvale}
{OwnerName Alice Age 30 City {San Jose}}
{OwnerName Mike Age 50 City {San Jose}}
{OwnerName Jim Age 42 City {San Francisco}}
}
}
% relformat $OWNER OWNER
+=========+---+-------------+
|OwnerName|Age|City |
|string |int|string |
+=========+---+-------------+
|Sue |24 |Cupertino |
|George |35 |Sunnyvale |
|Alice |30 |San Jose |
|Mike |50 |San Jose |
|Jim |42 |San Francisco|
+=========+---+-------------+
OWNER
-----
% set OWNERSHIP {
Relation
{OwnerName string DogName string Acquired string}
{{OwnerName DogName}}
{
{OwnerName Sue DogName Fido Acquired 2001}
{OwnerName Sue DogName Sam Acquired 2000}
{OwnerName George DogName Fido Acquired 2001}
{OwnerName George DogName Sam Acquired 2000}
{OwnerName Alice DogName Spot Acquired 2001}
{OwnerName Mike DogName Rover Acquired 2002}
{OwnerName Jim DogName Fred Acquired 2003}
}
}
% relformat $OWNERSHIP OWNERSHIP
+=========+=======+--------+
|OwnerName|DogName|Acquired|
|string |string |string |
+=========+=======+--------+
|Sue |Fido |2001 |
|Sue |Sam |2000 |
|George |Fido |2001 |
|George |Sam |2000 |
|Alice |Spot |2001 |
|Mike |Rover |2002 |
|Jim |Fred |2003 |
+=========+=======+--------+
OWNERSHIP
---------
|
- ::ral::relation array relationValue arrayVarName ?keyAttr valueAttr?
-
The array subcommand converts the relation value
given by relationValue into an array variable named arrayVarName.
The relationValue must either
be a binary relation with a single identifier that has a single attribute
or the keyAttr and valueAttr arguments must be supplied.
The array variable will be created if necessary.
For a binary relation,
the values of the identifying attribute of relationValue will become
the array indices of arrayVarName
the other attribute values will be set to the corresponding array values.
When the optional keyAttr and valueAttr are supplied, the
the values of keyAttr are used as the array indices and the corresponding
values of valueAttr are the array value.
Note, that if a supplied keyAttr is not an identifier then it is
possible that more than one tuple in relationValue will have the
same value for keyAttr.
In this case the array value from valueAttr
corresponding to duplicated values of
keyAttr is arbitrarily chosen by the implementation.
Thus the safe approach is to either project any relation value that is
to be converted into an array to be a
binary relation or to tag the relation and use the tag attribute name
as keyAttr thereby insure that no duplicated array indices can occur.
|
% relation array $DOG dogarray
% parray dogarray
dogarray(Fido) = Poodle
dogarray(Fred) = Spaniel
dogarray(Jumper) = Mutt
dogarray(Rover) = Retriever
dogarray(Sam) = Collie
dogarray(Spot) = Terrier
|
- ::ral::relation assign relationValue ?attrName | attr-var-pair ...?
-
The assign subcommand is short hand for
tuple assign [relation tuple relationValue] ?...?.
This allow moving the values of a relation with a single tuple into
ordinary Tcl variable.
|
% relation foreach d $DOG -descending DogName {
relation assign $d DogName
puts $DogName
}
Spot
Sam
Rover
Jumper
Fred
Fido
|
- ::ral::relation attributes relationValue
-
The attributes subcommand returns the names of the attributes of
relationValue as a list.
|
% relation attributes $DOG
DogName Breed
% relation attributes $OWNER
OwnerName Age City
|
- ::ral::relation body relationValue
-
The body subcommand returns the body of the relation value
given by relationValue.
The body is a list of tuple values, each tuple value being in turn
a list of attribute name / attribute value pairs.
The order of the tuple values in the body list is arbitrary.
|
% foreach t [relation body $DOG] {puts $t}
DogName Fido Breed Poodle
DogName Sam Breed Collie
DogName Spot Breed Terrier
DogName Rover Breed Retriever
DogName Fred Breed Spaniel
DogName Jumper Breed Mutt
|
- ::ral::relation cardinality relationValue
-
The cardinality subcommand returns the number tuples contained
in the body of relationValue.
|
% relation cardinality $DOG
6
% relation cardinality $OWNERSHIP
7
|
- ::ral::relation choose relationValue attr value ?attr2 value2 ...?
-
The choose subcommand returns a new relation
that has the same heading as relationValue and a body consisting
of the set of tuples in relationValue whose identifying attribute values
match those given as the attr value arguments.
The cardinality of the returned relation will necessarily then be either 0 or 1.
The attr value arguments must be given in pairs
with attribute names alternating with attribute values.
The set of attribute names given must form one of the
identifiers of relationValue.
If relationValue contains a tuple whose attribute values match those
given then the returned relation will contain that single tuple.
Otherwise the returned relation has cardinality 0.
This subcommand is useful in those contexts where the attribute values of an
identifier are known and evaluating an expression over all the tuples
in relationValue is superfluous.
|
% relformat [relation choose $::DOG DogName Fred]
+=======+-------+
|DogName|Breed |
|string |string |
+=======+-------+
|Fred |Spaniel|
+=======+-------+
% relformat [relation choose $::DOG DogName Jane]
+=======+------+
|DogName|Breed |
|string |string|
+=======+------+
+=======+------+
|
- ::ral::relation compose relationValue1 relationValue2 ?-using attrList? ?relationValue3 ...?
-
The compose subcommand computes the join of relationValue1
and relationValue2 but eliminates all of the attributes used in the
join.
The returned relation has a heading the same as the union of the headings
of relationValue1 and relationValue2 minus all of the
join attributes from the two relations.
The returned relation has a body that is the same as that of the
join minus any duplicated tuples that result when the join
attributes are eliminated.
As with join, if the -using argument are missing, the
join is computed across the attributes in relationValue1 and
relationValue2 that are named the same.
Otherwise the attrList argument is treated the same as for the
join subcommand.
- ::ral::relation create attrs ids ?tuple1 tuple2 ...?
-
The create subcommand returns the relation value described by
the attrs, ids and tupleN arguments.
The attrs argument is a list of attribute name / attribute type pairs.
The ids argument is a list of identifiers, each identifier in turn
being a list of one or more attribute names.
Any tuples given by the ?tupleN? arguments is inserted into the
relation value.
Each tupleN argument is a list of attribute name / attribute value pairs.
This command allows for creating a relation value without having knowledge of
the string representation of a relation value. Compare with the
::ral::tuple create command.
|
% relation create {DogName string Breed string} DogName {DogName Fido Breed Poodle}
Relation {DogName string Breed string} DogName {{DogName Fido Breed Poodle}}
|
- ::ral::relation degree relationValue
-
The degree subcommand returns the number of attributes in the
heading of relationValue
- ::ral::relation dict relationValue ?keyAttr valueAttr?
-
The dict subcommand returns a dictionary object for an appropriately
structured relationValue.
The relationValue must either
be a binary relation with a single identifier that has a single attribute
or the optional keyAttr and valueAttr must be given.
If the relation is binary, then
the returned dictionary will have the values of the identifying attribute
as the dictionary keys and the other attribute values
as the corresponding dictionary values.
If the keyAttr and valueAttr arguments are given, then
the value in the tuples corresponding to keyAttr will be the dictionary
keys and the corresponding value of valueAttr will be the dictionary
values.
The same conditions for values of keyAttr that do not correspond
to an identifying attribute of relationValue decribed above
for the relation array command apply to this command also.
|
% dict for {name breed} [relation dict $::DOG] {
puts "$name ==> $breed"
}
Fred ==> Spaniel
Sam ==> Collie
Rover ==> Retriever
Spot ==> Terrier
Fido ==> Poodle
Jumper ==> Mutt
|
- ::ral::relation divide dividend divisor mediator
-
The divide subcommand implements the relational divide operation.
The headings of dividend and divisor must be disjoint and
the heading of mediator must be the union of the dividend
and divisor headings.
The returned result is a new relation that has the same heading as
dividend and contains all the tuples from dividend whose
corresponding tuples in mediator include all the tuples in
divisor.
Using the data from our ongoing example, then the following example shows
how division can be used to find all the Dogs owned by both Sue and George.
|
% set dividend [relation project $::DOG DogName]
Relation {DogName string} DogName {{DogName Fido} {DogName Sam} {DogName Spot} {DogName Rover} {DogName Fred} {DogName Jumper}}
% puts [relformat $dividend Dividend:]
+=======+
|DogName|
|string |
+=======+
|Fido |
|Sam |
|Spot |
|Rover |
|Fred |
|Jumper |
+=======+
Dividend:
---------
% set divisor [relation project [relation restrict $::OWNER t {[tuple extract $t OwnerName] eq "Sue" || [tuple extract $t OwnerName] eq "George"}] OwnerName]
Relation {OwnerName string} OwnerName {{OwnerName Sue} {OwnerName George}}
% puts [relformat $divisor Divisor:]
+=========+
|OwnerName|
|string |
+=========+
|Sue |
|George |
+=========+
Divisor:
--------
% set mediator [relation eliminate $::OWNERSHIP Acquired]
Relation {OwnerName string DogName string} {{OwnerName DogName}} {{OwnerName Sue DogName Fido} {OwnerName Sue DogName Sam} {OwnerName George DogName Fido} {OwnerName George DogName Sam} {OwnerName Alice DogName Spot} {OwnerName Mike DogName Rover} {OwnerName Jim DogName Fred}}
% puts [relformat $mediator Mediator:]
+=========+=======+
|OwnerName|DogName|
|string |string |
+=========+=======+
|Sue |Fido |
|Sue |Sam |
|George |Fido |
|George |Sam |
|Alice |Spot |
|Mike |Rover |
|Jim |Fred |
+=========+=======+
Mediator:
---------
% set quotient [relation divide $dividend $divisor $mediator]
Relation {DogName string} DogName {{DogName Fido} {DogName Sam}}
% puts [relformat $quotient "All dogs owned by both Sue and George"]
+=======+
|DogName|
|string |
+=======+
|Fido |
|Sam |
+=======+
All dogs owned by both Sue and George
-------------------------------------
|
- ::ral::relation eliminate relationValue ?attribute ...?
-
The eliminate subcommand returns a new relation that has a heading
equal to that of the relationValue minus any attributes whose names
are given in the attribute arguments.
The body of the new relation is the same as the body of relationValue
removing any tuples that might be duplicated as a result of removing the
attributes.
The eliminate subcommand complements the project command
in the sense that eliminate specifies which attributes
to discard and project specifies which attribute to keep.
|
% relformat [relation eliminate $::DOG Breed]
+=======+
|DogName|
|string |
+=======+
|Fido |
|Sam |
|Spot |
|Rover |
|Fred |
|Jumper |
+=======+
|
- ::ral::relation emptyof relationValue
-
The emptyof subcommand returns a new relation that has the same
heading as relationValue but whose cardinality is zero.
- ::ral::relation extend relationValue tupleVariable ?attr1 type1 expr1 attr2 type2 expr2 ...?
-
The extend subcommand returns a new relation which has the same
heading as relationValue with zero or more additional attributes.
The first additional attribute is given by attr1 which has
type type1 and its value is
set to the result returned by passing expr1 to the expr command.
Subsequent attributes are treated similarly.
As each tuple in the body of relationValue is considered, its
value is set into the variable whose name is given by the tupleVariable
argument.
This variable is accessible to the extending expressions so that the
current tuple values of relationValue are available for computing
the values of the new attributes.
|
% relformat [relation extend $::OWNER o AgeInMonths int {[tuple extract $o Age] * 12}]
+=========+---+-------------+-----------+
|OwnerName|Age|City |AgeInMonths|
|string |int|string |int |
+=========+---+-------------+-----------+
|Sue |24 |Cupertino |288 |
|George |35 |Sunnyvale |420 |
|Alice |30 |San Jose |360 |
|Mike |50 |San Jose |600 |
|Jim |42 |San Francisco|504 |
+=========+---+-------------+-----------+
|
- ::ral::relation extract relationValue attrName ?attrName2 ...?
-
The extract subcommand is short hand for
tuple extract [relation tuple relationValue] attrName ?...?.
This command obtains one or more attribute values from a relation that
is of cardinality one.
- ::ral::relation foreach relationVariable relationValue ?-ascending | -descending? ?attr-list? script
-
The foreach subcommand provides a means to iterate through the
body of a relation.
For each tuple in the body of relationValue,
the relationVariable variable is successively set to a relation
value that contains a single tuple from relationValue and then
script is executed.
The order in which the tuples are considered is unspecified unless
a list of sorting attributes is specified by the attr-list argument.
In this case,
the tuples are visited in the -ascending order of
the values of the sorting attibutes if the direction option
of -ascending is supplied or if no direction option is given.
Tuples can be visited in descending order of the sorting attributes if
the -descending option is given.
|
% relation foreach d $DOG -descending DogName {
puts [tuple extract [relation tuple $d] DogName]
}
Spot
Sam
Rover
Jumper
Fred
Fido
|
- ::ral::relation group relationValue newattribute ?attr1 attr2 ...?
-
The group subcommand creates a new relation from relationValue
that contains an attribute which is of type Relation.
The newattribute argument gives the name of the relation valued
attribute and
the attrN arguments give the names of attributes in
relationValue that are to be assembled into a relation value.
The returned relation has a heading that is the same as relationValue
minus the attributes given in the attrN arguments plus the
new relation attribute given by newattribute.
The resulting body has tuples for each unique set of values for the
remaining ungrouped attributes in the original relation with the
corresponding part of the tuple placed in the new relation valued attribute.
See also the ungroup subcommand for the complementary operation.
|
% relformat [relation group $::OWNERSHIP DogAcquisition DogName Acquired]
+=========+------------------+
|OwnerName|DogAcquisition |
|string |Relation |
+=========+------------------+
|Sue |+=======+--------+|
| ||DogName|Acquired||
| ||string |string ||
| |+=======+--------+|
| ||Fido |2001 ||
| ||Sam |2000 ||
| |+=======+--------+|
|George |+=======+--------+|
| ||DogName|Acquired||
| ||string |string ||
| |+=======+--------+|
| ||Fido |2001 ||
| ||Sam |2000 ||
| |+=======+--------+|
|Alice |+=======+--------+|
| ||DogName|Acquired||
| ||string |string ||
| |+=======+--------+|
| ||Spot |2001 ||
| |+=======+--------+|
|Mike |+=======+--------+|
| ||DogName|Acquired||
| ||string |string ||
| |+=======+--------+|
| ||Rover |2002 ||
| |+=======+--------+|
|Jim |+=======+--------+|
| ||DogName|Acquired||
| ||string |string ||
| |+=======+--------+|
| ||Fred |2003 ||
| |+=======+--------+|
+=========+------------------+
|
- ::ral::relation heading relationValue
-
The heading subcommand returns the relation heading of the
relationValue.
The heading is a three element list consisting of the keyword
Relation, a list of attributes and types and a list of identifiers.
|
% relation heading $DOG
Relation {DogName string Breed string} DogName
|
- ::ral::relation identifiers relationValue
-
The identifiers subcommand returns the set of identifiers for the
relation.
The identifiers are returned as a list each element of which is in turn
a list of attribute names that constitute the identifer.
- ::ral::relation include relationValue ?name-value-list1 name-value-list2 ...?
-
The include subcommand returns a new relation that has the same
heading as relationValue and a body consisting of the body of
relationValue with additional tuples formed by inserting the
values given in the name-value-listN arguments.
Each name-value-list argument consists of a list of alternating
attribute names and attribute values.
All attributes in the heading of relationValue must appear in
each name-value-list argument.
It is an error to attempt to include duplicate tuples in the relation.
This is a convenience command that is useful when building relation values
for other program data.
|
% set d [relation emptyof $DOG]
Relation {DogName string Breed string} DogName {}
% relformat [relation include $d {DogName Alfonse Breed Dalmation} {DogName Puffy Breed {Toy Poodle}}]
+=======+----------+
|DogName|Breed |
|string |string |
+=======+----------+
|Alfonse|Dalmation |
|Puffy |Toy Poodle|
+=======+----------+
|
- ::ral::relation intersect relationValue1 relationValue2 ?relationValue3 ...?
-
The intersect subcommand returns the set intersection of two or
more relations.
All relations must be of the same type.
The result relation has a heading that is the same as any of the arguments
and has a body consisting of all tuples present in all of the
relationValue arguments.
Since the intersection operation is both associative and commutative,
the order of the relationValue arguments has no effect the result.
- ::ral::relation is relationValue1 compareop relationValue2
-
The is subcommand returns a boolean value based on performing a
comparison operation between two relation values.
Allowed values of compareop are:
- equal | ==
-
Returns 1 if relationValue1 is equal to relationValue2.
- notequal | !=
-
Returns 1 if relationValue1 is not equal to relationValue2.
- propersubsetof | <
-
Returns 1 if relationValue1 is a proper subset of relationValue2.
- subsetof | <=
-
Returns 1 if relationValue1 is a subset of relationValue2.
- propersupersetof | >
-
Returns 1 if relationValue1 is a proper superset of relationValue2.
- supersetof | >=
-
Returns 1 if relationValue1 is a superset of relationValue2.
Both relationValue1 and relationValue2 must be of the same
type to be compared.
|
% set sDogs [relation restrictwith $DOG {[string match S* $DogName]}]
Relation {DogName string Breed string} DogName {{DogName Sam Breed Collie} {DogName Spot Breed Terrier}}
% relation is $DOG == $sDogs
0
% relation is $DOG != $sDogs
1
% relation is $DOG supersetof $sDogs
1
% relation is $DOG > $sDogs
1
% relation is $DOG propersubsetof $sDogs
0
% relation is $DOG <= $sDogs
0
|
- ::ral::relation isempty relationValue
-
The isempty subcommand returns the boolean value "1" if the
body of relationValue does not contain any tuples and "0" otherwise.
The isempty subcommand is a convenient short hand for the the command
expr {[::ral::relation cardinality relationValue] == 0}.
- ::ral::relation isnotempty relationValue
-
The isnotempty subcommand returns the boolean value "1" if the
body of relationValue contains any tuples and "0" otherwise.
The isnotempty subcommand is a convenient short hand for the the command
expr {[::ral::relation cardinality relationValue] != 0}.
- ::ral::relation join relationValue1 relationValue2 ?-using attrList? ?relationValue3 ...? ?-using attrList2?
-
The join subcommand performs the natural join of
relationValue1 with relationValue2.
The join is performed across the given attrList.
If no attrList are given, then the join is performed across
attributes with the same name in both relations
(because of the rename subcommand it is always possible to arrange
for the relations to have common names for the join attributes).
If present, the attrList is a list of pairs of attribute names.
The even numbered elements
give the name of a join attribute in relationValue1 and the
odd numbered elements give the name of the corresponding
join attribute in relationValue2.
The heading of the resulting relation consists of all the attibutes of
relationValue1 plus all the attributes of relationValue2
minus any of the join attributes from relationValue2.
The body of the resulting relation consists all tuples composed from the
tuples in both relationValue1 and relationValue2 where the values of
the join attributes in relationValue1 equal those of relationValue2.
Several relations can be joined by optionally listing them as additional
relationValueN arguments.
Additional ?-using? arguments may be given for each pair of
relationValue arguments to specify the attributes across which the
join is to be performed.
The ?-using? options are a convenient short hand for having to
rename attributes to achieve common attribute names.
The join operation is both associative and commutative and so the order
of the relationValueN does not affect the result.
|
% relformat [relation join $OWNERSHIP $DOG]
+=========+=======+--------+---------+
|OwnerName|DogName|Acquired|Breed |
|string |string |string |string |
+=========+=======+--------+---------+
|Sue |Fido |2001 |Poodle |
|Sue |Sam |2000 |Collie |
|George |Fido |2001 |Poodle |
|George |Sam |2000 |Collie |
|Alice |Spot |2001 |Terrier |
|Mike |Rover |2002 |Retriever|
|Jim |Fred |2003 |Spaniel |
+=========+=======+--------+---------+
|
- ::ral::relation list relationValue ?attrName?
-
The list subcommand returns the values of a single attribute
from all the tuples of relationValue as a proper Tcl list.
If attrName is not given, then
RelationValue must be of degree one or an error is returned.
Note that the list returned from a singular relation is necessarily a set
and may be used with the struct::set package.
If attrName is present, then the returned list will consist of the
value of the given attribute taken from all the tuples in the relation
in an arbitrary order.
In this case if attrName does not constitute an identifier of
relationValue, then, in general, the returned list is not a set.
|
% relation list [relation project $OWNERSHIP Acquired]]
2001 2000 2002 2003
|
- ::ral::relation minus relationValue1 relationValue2
-
The minus subcommand returns the set difference between two relations.
The relationValue arguments must be of the same type and that is the
type of the result relation.
The body of the result consists of those tuples present in
relationValue1 but not present in relationValue2.
Note that the order of the relationValue1 and relationValue2
arguments is significant to the result,
i.e. minus is not a commutative operation.
- ::ral::relation project relationValue ?attr1 attr2 ...?
-
The project subcommand returns a relation whose heading consists of
only those attributes listed in the attrN arguments.
The body of the result consists of tuples the corresponding tuples from
relationValue, removing any duplicates created by considering only
a subset of the attributes.
|
% relformat [relation project $OWNER City]
+=============+
|City |
|string |
+=============+
|Cupertino |
|Sunnyvale |
|San Jose |
|San Francisco|
+=============+
|
- ::ral::relation rank relationValue ?-ascending | -descending? rankAttr newAttr
-
The rank subcommand returns a new relation whose heading is the same
as relationValue extending by an attribute named newAttr.
The type of newAttr will be int and its value will be set
to the number of tuples in relationValue where the value of
rankAttr is less than or equal to (?-descending?) or
greater than or equal to (?-ascending?) that of the given tuple.
The default ranking is -ascending.
The type of rankAttr must be int, double, or string.
The rank command is useful when it is desirable to limit the
number of tuples in the result.
For example, to find the names and ages of the two oldest owners:
|
% set ro [relation rank $OWNER -descending Age AgeRank]
Relation {OwnerName string Age int City string AgeRank int} OwnerName {{OwnerName Sue Age 24 City Cupertino AgeRank 5} {OwnerName George Age 35 City Sunnyvale AgeRank 3} {OwnerName Alice Age 30 City {San Jose} AgeRank 4} {OwnerName Mike Age 50 City {San Jose} AgeRank 1} {OwnerName Jim Age 42 City {San Francisco} AgeRank 2}}
% relformat [relation project [relation restrictwith $ro {$AgeRank <= 2}] OwnerName Age]
+=========+---+
|OwnerName|Age|
|string |int|
+=========+---+
|Mike |50 |
|Jim |42 |
+=========+---+
|
- ::ral::relation reidentify relationValue id1 ?id2 id3 ...?
-
The reidentify subcommand returns a relation whose attributes are
the same as relationValue but whose identifiers are those given
by the idN arguments.
The body of the returned relation value is the same as relationValue minus
any tuples that are duplicates with respect to the new set of identifiers.
Normally, identifiers are properly inferred by the relation subcommands.
However in certain contexts, the programmer may have knowledge of the
contents of a relation value and wish to force an identification scheme
that takes advantage of that knowledge.
This command can be considered complementary to the rename subcommand.
- ::ral::relation rename relationValue ?oldname newname ...?
-
The rename subcommand returns a relation whose heading has each
oldname attribute changed to newname and whose body is the
same as relationValue.
An arbitrary number of oldname / newname pairs may be given.
Renaming is processed from left to right in the command arguments
and it is not an error to change the name of any given attribute multiple times.
However, oldname must always be the name of an attribute at the
time the rename takes place.
The rename subcommand is useful for manipulating the attribute names
of a relation to suit the needs of particular operators (e.g.
times and join).
|
% relformat [relation rename $OWNER City Town]
+=========+---+-------------+
|OwnerName|Age|Town |
|string |int|string |
+=========+---+-------------+
|Sue |24 |Cupertino |
|George |35 |Sunnyvale |
|Alice |30 |San Jose |
|Mike |50 |San Jose |
|Jim |42 |San Francisco|
+=========+---+-------------+
% relformat [relation rename $OWNER City Town City Village]
unknown attribute name, "City"
|
- ::ral::relation restrict relationValue tupleVariable expression
-
The restrict subcommand returns a new relation that is a
subset (possibly improper) of relationValue.
Each tuple in the body of relationValue is successively assigned
to tupleVariable and expression is evaluated.
The resulting relation has a heading that is the same as relationValue
and a body consisting of all tuples where expression evaluated to true.
|
% relformat [relation restrict $DOG d {[string match S* [tuple extract $d DogName]]}]
+=======+-------+
|DogName|Breed |
|string |string |
+=======+-------+
|Sam |Collie |
|Spot |Terrier|
+=======+-------+
|
- ::ral::relation restrictwith relationValue expression
-
The restrictwith subcommand behaves like the restrict subcommand
except that the values of the tuple attributes are
placed in Tcl variables that have
the same name as the attributes.
Each tuple in the body of relationValue is successively considered
and each attribute of the tuple is assigned to a Tcl variable that is the
same name as the attribute and expression is evaluated.
The resulting relation has a heading that is the same as relationValue
and a body consisting of all tuples where expression evaluated to true.
The restrictwith subcommand is roughly equal to performing a
tuple assign command on each tuple in relationValue before
evaluating expression.
The attribute variables are created if needed and will overwrite the values
of any variables that are named the same.
Also, the variables are deleted after the command completes.
Also note that restrictwith will not function correctly if nested
with a more complex expression that also contains a restrictwith
command for a relationValue with the same heading. In this case
the invocation of one restrictwith may very well overwrite the
variables of a separate invocation.
With that restriction in mind,
the restrictwith subcommand is often more convenient than
performing all the required tuple extract commands that are
otherwise required.
|
% relformat [relation restrictwith $DOG {[string match S* $DogName]}]
+=======+-------+
|DogName|Breed |
|string |string |
+=======+-------+
|Sam |Collie |
|Spot |Terrier|
+=======+-------+
% puts $DogName
can't read "DogName": no such variable
|
- ::ral::relation semijoin relationValue1 relationValue2 ?-using attrList? ?relationValue3 ...?
-
The semijoin subcommand computes the join of relationValue1
and relationValue2 but eliminates all of the attributes of
relationValue1
(or alternatively speaking, projecting all attributes of relationValue2).
The returned relation has a heading the same as relationValue2
and a body consisting of those tuples in relationValue2 that
would have been included in the natural join with relationValue1.
As with join, if the -using argument are missing, the
join is computed across the attributes in relationValue1 and
relationValue2 that are named the same.
Otherwise the attrList argument is treated the same as for the
join subcommand.
Also like the join subcommand,
additional relationValue arguments may be given and the
result is computed in left to right order.
This implies that the type of the result is always the type of the right
most relationValue.
N.B. the sense of this command is inverted from previous versions of
this library.
For example, to find all the dogs that have some owner:
|
% relformat [relation semijoin $OWNERSHIP $DOG]
+=======+---------+
|DogName|Breed |
|string |string |
+=======+---------+
|Fido |Poodle |
|Sam |Collie |
|Spot |Terrier |
|Rover |Retriever|
|Fred |Spaniel |
+=======+---------+
|
- ::ral::relation semiminus relationValue1 relationValue2 ?-using attrList? ?relationValue3 ...?
-
The semiminus subcommand computes the difference between
relationValue2 and the semijoin of relationValue1 and
relationValue2.
The returned relation has a heading equal to that of relationValue2
and a body consisting of those tuples from relationValue2 which would
not have been included in the natural join of relationValue1
and relationValue2.
The optional -using argument is treated in the same way as for
the join subcommand.
Also like the semijoin subcommand, additional relationValue
arguments may be given.
N.B. the sense of this command is inverted from previous versions of
this library.
For example, to find all dogs that have no owner:
|
% relformat [relation semiminus $OWNERSHIP $DOG]
+=======+------+
|DogName|Breed |
|string |string|
+=======+------+
|Jumper |Mutt |
+=======+------+
|
- ::ral::relation summarize relationValue perRelation relationVarName attr type expression ?attr type expression ...?
-
The summarize subcommand allows for computations across sets of
attributes.
The perRelation must be of the same type as a projection of
relationValue.
The returned relation has the same heading as perRelation extended
by attr.
The attr gives the name of the new attribute.
The name of the new attribute may not match any existing attributes in
perRelation.
The type argument is data type of the new attribute.
Several new attributes may be added in one summarize command.
The body of the returned relation consists of all the tuples of
perRelation with values for the new attributes.
Those values are computed by evaluating the summmary arguments
as an expression.
Before evaluating expression for a tuple in perRelation,
relationVarName is set to a relation value consisting of
all the tuples in relationValue whose attributes match the
corresponding attributes in perRelation.
The expression expression may then access the value of that relation
using the given relationVarName variable name.
The expression is expected to return a result of the
same type as the new attribute.
In this example we determine the years when dogs were acquired and the
number of dogs acquired in each year.
|
% set ac [relation project $OWNERSHIP Acquired]
Relation {Acquired string} Acquired {{Acquired 2001} {Acquired 2000} {Acquired 2002} {Acquired 2003}}
% relformat [relation summarize $OWNERSHIP $ac s NumAcquired int {[relation cardinality $s]}]
+========+-----------+
|Acquired|NumAcquired|
|string |int |
+========+-----------+
|2001 |3 |
|2000 |2 |
|2002 |1 |
|2003 |1 |
+========+-----------+
|
The summarize command can also be used to perform
more complicated computations. In the case of summarizing over the
dee relation gives the ability to compute overall totals or
averages.
In this example we compute the average age of the owners.
|
proc ravg {rel attr} {
set sum 0
relation foreach r $rel {
tuple assign [relation tuple $r]
incr sum $Age
}
return [expr {$sum / [relation cardinality $rel]}]
}
% set dee {Relation {} {{}} {{}}}
Relation {} {{}} {{}}
% relformat [relation summarize $OWNER $dee o AverageAge int {[ravg $o Age]}]
+==========+
|AverageAge|
|int |
+==========+
|36 |
+==========+
|
- ::ral::relation tag relationValue ?-ascending | -descending sort-attr-list? ?-within idsubset-attr-list? attrName
-
The tag subcommand creates a new relation which has the same heading
as relationValue extended by a new attribute named attrName.
The type of attrName will be int and will have the values
between 0 and the cardinality of relationValue minus one.
The tuples in relationValue will be extended in either ascending
or descending order of the sort-attr-list.
If no sort-attr-list argument is given,
then the tagging order is arbitrary.
If the ?-within? argument is given then the attribute names given
in idsubset-attr-list must consist of all the attributes of some
identifier of relationValue except one.
In this case,
the values of attrName will be unique within the subset of tuples which
match the values of idsubset-attr-list
and a new identifiers is created consisting of the attributes in
idsubset-attr-list plus attrName.
The tag command is useful when a full ordering needs to be placed
on a relation.
For example, tagging a relation will allow projecting both the tag and
another, non-identifying attribute without loosing any values.
|
% relformat [relation tag $DOG -ascending DogName DogId]
+=======+---------+=====+
|DogName|Breed |DogId|
|string |string |int |
+=======+---------+=====+
|Fido |Poodle |0 |
|Fred |Spaniel |1 |
|Jumper |Mutt |2 |
|Rover |Retriever|3 |
|Sam |Collie |4 |
|Spot |Terrier |5 |
+=======+---------+=====+
% relformat [relation tag $OWNERSHIP -ascending OwnerName -within DogName DogId]
+=========+=======+--------+=====+
|OwnerName|DogName|Acquired|DogId|
|string |string |string |int |
+=========+=======+--------+=====+
|Alice |Spot |2001 |0 |
|George |Fido |2001 |0 |
|George |Sam |2000 |0 |
|Jim |Fred |2003 |0 |
|Mike |Rover |2002 |0 |
|Sue |Fido |2001 |1 |
|Sue |Sam |2000 |1 |
+=========+=======+--------+=====+
|
- ::ral::relation tclose relationValue
-
The tclose subcommand returns a new relation value that is the
transitive closure of relationValue.
The relationValue must be a binary relation and each attribute must
be of the same type.
The returned relation has a heading that is the same as relationValue.
The pairs of attribute values in relationValue may be considered as
defining the edges of a graph.
The body of the transitive closure will contain all pairs of the two
attributes where there exists some path between the vertices in the implied
graph.
The original relationValue is necessarily a subset of the transitive
closure relation.
The tclose subcommand often useful when there is a hierarchical
relationship among the data values.
Consider the employee / supervisor reporting relationship.
If we are interested in all people who report directly or indirectly
to John, then we have:
|
% set REPORTS_TO {
Relation
{Employee string Supervisor string}
{{Employee Supervisor}}
{
{Employee Sue Supervisor John}
{Employee Bob Supervisor John}
{Employee Jane Supervisor Sue}
{Employee Joe Supervisor Sue}
{Employee Carl Supervisor Bob}
{Employee James Supervisor Alice}
}
}
% relformat [relation project [relation restrictwith [relation tclose $REPORTS_TO] {$Supervisor eq "John"} ] Employee ] "Direct/Indirect Reports to John"
+========+
|Employee|
|string |
+========+
|Sue |
|Bob |
|Jane |
|Joe |
|Carl |
+========+
Direct/Indirect Reports to John
-------------------------------
|
- ::ral::relation times relationValue1 relationValue2 ?relationValue3 ...?
-
The times subcommand returns the extended Cartesian product of two or
more relations.
The heading of the result is the union of the headings of all
the relationValue arguments.
The body of the result consists of a tuple for all combinations of the tuples
in all the relationValue arguments.
Since the relational multiplication operation is both
associative and commutative,
the order of the relationValue arguments has no effect on the result.
|
% relformat [relation times $DOG $OWNER]
+=======+---------+=========+---+-------------+
|DogName|Breed |OwnerName|Age|City |
|string |string |string |int|string |
+=======+---------+=========+---+-------------+
|Fido |Poodle |Sue |24 |Cupertino |
|Fido |Poodle |George |35 |Sunnyvale |
|Fido |Poodle |Alice |30 |San Jose |
|Fido |Poodle |Mike |50 |San Jose |
|Fido |Poodle |Jim |42 |San Francisco|
|Sam |Collie |Sue |24 |Cupertino |
|Sam |Collie |George |35 |Sunnyvale |
|Sam |Collie |Alice |30 |San Jose |
|Sam |Collie |Mike |50 |San Jose |
|Sam |Collie |Jim |42 |San Francisco|
|Spot |Terrier |Sue |24 |Cupertino |
|Spot |Terrier |George |35 |Sunnyvale |
|Spot |Terrier |Alice |30 |San Jose |
|Spot |Terrier |Mike |50 |San Jose |
|Spot |Terrier |Jim |42 |San Francisco|
|Rover |Retriever|Sue |24 |Cupertino |
|Rover |Retriever|George |35 |Sunnyvale |
|Rover |Retriever|Alice |30 |San Jose |
|Rover |Retriever|Mike |50 |San Jose |
|Rover |Retriever|Jim |42 |San Francisco|
|Fred |Spaniel |Sue |24 |Cupertino |
|Fred |Spaniel |George |35 |Sunnyvale |
|Fred |Spaniel |Alice |30 |San Jose |
|Fred |Spaniel |Mike |50 |San Jose |
|Fred |Spaniel |Jim |42 |San Francisco|
|Jumper |Mutt |Sue |24 |Cupertino |
|Jumper |Mutt |George |35 |Sunnyvale |
|Jumper |Mutt |Alice |30 |San Jose |
|Jumper |Mutt |Mike |50 |San Jose |
|Jumper |Mutt |Jim |42 |San Francisco|
+=======+---------+=========+---+-------------+
|
- ::ral::relation tuple relationValue
-
The tuple subcommand returns the body of relationValue as a tuple.
The cardinality of relationValue must be one or an error is returned.
- ::ral::relation ungroup relationValue attribute
-
The ungroup subcommand maps relations that have relation valued
attributes to relations that have scalar valued attributes.
It is the complementary operation to the group command.
The attribute argument must be the name of a relation valued
attribute of relationValue.
The returned relation has a heading consisting of all the attributes of
relationValue minus attribute plus all the attributes of the
attribute relation.
The body of the returned relation consists of tuples composed of pairing
each tuple from the attribute attribute with its corresponding
components from relationValue.
|
set OwnerContacts {
Relation
{OwnerName string Contact {Relation {Type string Number string} Type}}
OwnerName
{
{OwnerName Sue Contact {
{Type Home Number 555-1212}
{Type Work Number 555-6635}}
}
{OwnerName George Contact {
{Type Home Number 555-8810}
{Type Work Number 555-1177}
{Type Mobile Number 555-3399}}
}
}
}
% relformat $OwnerContacts
+=========+-----------------+
|OwnerName|Contact |
|string |Relation |
+=========+-----------------+
|Sue |+======+--------+|
| ||Type |Number ||
| ||string|string ||
| |+======+--------+|
| ||Home |555-1212||
| ||Work |555-6635||
| |+======+--------+|
|George |+======+--------+|
| ||Type |Number ||
| ||string|string ||
| |+======+--------+|
| ||Home |555-8810||
| ||Work |555-1177||
| ||Mobile|555-3399||
| |+======+--------+|
+=========+-----------------+
% relformat [relation ungroup $OwnerContacts Contact]
+=========+======+--------+
|OwnerName|Type |Number |
|string |string|string |
+=========+======+--------+
|Sue |Home |555-1212|
|Sue |Work |555-6635|
|George |Home |555-8810|
|George |Work |555-1177|
|George |Mobile|555-3399|
+=========+======+--------+
|
- ::ral::relation union relationValue1 relationValue2 ?relationValue3 ...?
-
The union subcommand returns the set union of two or more relations.
All relations must be of the same type.
The result relation has a heading that is the same as any of the arguments
and has a body consisting of all tuples present in any of the
relationValue arguments.
Since the union operation is both associative and commutative,
the order of the relationValue arguments has no effect the result.
relvar , tuple
body , relation , tuple
Copyright © 2004, 2005, 2006, 2007 by G. Andrew Mangogna