602 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			602 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 | 
						|
<html xmlns="http://www.w3.org/1999/xhtml">
 | 
						|
<head>
 | 
						|
<title>GT::SQL::Relation - manage multiple table joins</title>
 | 
						|
<link rev="made" href="mailto:root@penguin.office.gossamer-threads.com" />
 | 
						|
 | 
						|
<style type="text/css">
 | 
						|
/* $MVD$:fontset("Untitled Font Set 1","ARIEL","HELVETICA","HELV","SANSERIF") */
 | 
						|
/* $MVD$:fontset("Arial","Arial") */
 | 
						|
/* $MVD$:fontset("Arial Black","Arial Black") */
 | 
						|
/* $MVD$:fontset("Algerian","Algerian") */
 | 
						|
 | 
						|
 | 
						|
body {
 | 
						|
    background-color: white;
 | 
						|
    font-family: Verdana, Arial, sans-serif;
 | 
						|
    font-size: small;
 | 
						|
    color: black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
p {
 | 
						|
    background-color : white;
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
h1 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-weight : bold;
 | 
						|
    font-size : medium;
 | 
						|
    background-color : white;
 | 
						|
    color : maroon;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
h2 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : medium;
 | 
						|
    font-weight : bold;
 | 
						|
    color : blue;
 | 
						|
    background-color : white;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
h3 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-weight : bold;
 | 
						|
    font-size : medium;
 | 
						|
    color : black;
 | 
						|
    background-color : white;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
h4 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-weight : bold;
 | 
						|
    font-size : small;
 | 
						|
    color : maroon;
 | 
						|
    background-color : white;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
h5 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-weight : bold;
 | 
						|
    font-size : small;
 | 
						|
    color : blue;
 | 
						|
    background-color : white;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
h6 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-weight : bold;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
    background-color : white;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
ul {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
ol {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
dl {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
li {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
th {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
td {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
dl {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
dd {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
dt {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
code {
 | 
						|
    font-family : Courier;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
pre {
 | 
						|
    font-family : Courier;
 | 
						|
    font-size : small;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
.mvd-H1 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-weight : bold;
 | 
						|
    font-size : 14.0pt;
 | 
						|
    background-color : transparent;
 | 
						|
    background-image : none;
 | 
						|
    color : maroon;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
.mvd-H2 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : 12.0pt;
 | 
						|
    color : blue;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
p.indent {
 | 
						|
    font-family : "Verdana, Arial, sans-serif";
 | 
						|
    list-style-type : circle;
 | 
						|
    list-style-position : inside;
 | 
						|
    color : black;
 | 
						|
    margin-left : 16.0pt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
.mvd-P-indent {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    list-style-type : circle;
 | 
						|
    list-style-position : inside;
 | 
						|
    color : black;
 | 
						|
    margin-left : 16.0pt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
pre.programlisting {
 | 
						|
    font-size : 9.0pt;
 | 
						|
    list-style-type : disc;
 | 
						|
    margin-left : 16.0pt;
 | 
						|
    margin-top : -14.0pt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
.mvd-PRE-programlisting {
 | 
						|
    font-size : 9.0pt;
 | 
						|
    list-style-type : disc;
 | 
						|
    margin-left : 16.0pt;
 | 
						|
    margin-top : -14.0pt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
.mvd-PRE {
 | 
						|
    font-size : 9.0pt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
p.note {
 | 
						|
    margin-left : 28.0pt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
.mvd-P-note {
 | 
						|
    margin-left : 28.0pt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
.mvd-H4 {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-weight : normal;
 | 
						|
    font-size : 9.0pt;
 | 
						|
    color : black;
 | 
						|
    margin-left : 6.0pt;
 | 
						|
    margin-top : -14.0pt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
.mvd-P {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    font-size : 10.0pt;
 | 
						|
    color : black;
 | 
						|
}
 | 
						|
 | 
						|
.mvd-BODY {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    background-color : white;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
p.indentnobullet {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    list-style-type : none;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
.mvd-P-indentnobullet {
 | 
						|
    font-family : Verdana, Arial, sans-serif;
 | 
						|
    list-style-type : none;
 | 
						|
}
 | 
						|
</style>
 | 
						|
 | 
						|
 | 
						|
</head>
 | 
						|
 | 
						|
<body style="background-color: white">
 | 
						|
 | 
						|
<p><a name="__index__"></a></p>
 | 
						|
<!-- INDEX BEGIN -->
 | 
						|
 | 
						|
<ul>
 | 
						|
 | 
						|
	<li><a href="#name">NAME</a></li>
 | 
						|
	<li><a href="#synopsis">SYNOPSIS</a></li>
 | 
						|
	<li><a href="#description">DESCRIPTION</a></li>
 | 
						|
	<ul>
 | 
						|
 | 
						|
		<li><a href="#how_it_works">How it works</a></li>
 | 
						|
		<li><a href="#select_statements">SELECT statements</a></li>
 | 
						|
		<li><a href="#select_options">SELECT options</a></li>
 | 
						|
		<li><a href="#listing_the_relation_columns">Listing the relation columns</a></li>
 | 
						|
		<li><a href="#relation_primary_key">Relation primary key</a></li>
 | 
						|
		<li><a href="#foreign_keys_management">Foreign keys management</a></li>
 | 
						|
		<li><a href="#inserting_data">Inserting data</a></li>
 | 
						|
		<li><a href="#deleting_data">Deleting data</a></li>
 | 
						|
		<li><a href="#updating_records">Updating records</a></li>
 | 
						|
		<li><a href="#selecting_records">Selecting Records</a></li>
 | 
						|
	</ul>
 | 
						|
 | 
						|
	<li><a href="#copyright">COPYRIGHT</a></li>
 | 
						|
	<li><a href="#version">VERSION</a></li>
 | 
						|
</ul>
 | 
						|
<!-- INDEX END -->
 | 
						|
 | 
						|
<hr />
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h1><a name="name">NAME</a></h1>
 | 
						|
<p>GT::SQL::Relation - manage multiple table joins</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<hr />
 | 
						|
<h1><a name="synopsis">SYNOPSIS</a></h1>
 | 
						|
<pre>
 | 
						|
    my $relation = $DB->table('Company', 'Employees');
 | 
						|
    my $sth = $relation->select( {
 | 
						|
                    Company.Name => 'Gossamer Threads',
 | 
						|
                    Employees.Name => 'Alex Krohn'
 | 
						|
                }, ['Employees.Salary', 'Company.City'] );
 | 
						|
    my ($salary, $city) = $sth->fetchrow_array;
 | 
						|
    print "Alex works in $city and earns $salary!\n";</pre>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<hr />
 | 
						|
<h1><a name="description">DESCRIPTION</a></h1>
 | 
						|
<p>This module aims at emulating a set of tables that are related to each other
 | 
						|
via the use of foreign keys just as if it was one big table.</p>
 | 
						|
<p>The module interface should be as compatible as possible with GT::SQL::Table,
 | 
						|
thus you should be familiar with GT::SQL::Table before even reading this.</p>
 | 
						|
<p>This documentation explains the differences between GT::SQL::Relation and
 | 
						|
GT::SQL::Table and how the module internally works as well.</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="how_it_works">How it works</a></h2>
 | 
						|
<p>GT::SQL supports the concept of foreign keys (also known as external
 | 
						|
references). Basically, two tables that are linked together using external
 | 
						|
references can look like that:</p>
 | 
						|
<pre>
 | 
						|
    .-------------.      .---------.
 | 
						|
    | EMPLOYEE    |      | COMPANY |
 | 
						|
    `-------------'      `---------'
 | 
						|
    |  ID         |   .--->ID      |
 | 
						|
    |  COMPANY_ID ----'  | NAME    |
 | 
						|
    |  NAME       |      `---------'
 | 
						|
    |  SALARY     |
 | 
						|
    `-------------'</pre>
 | 
						|
<p>In this example, the COMPANY_ID attribute relates the fact that a an EMPLOYEE
 | 
						|
belongs to such or such COMPANY.</p>
 | 
						|
<p>Utilizing a Relation object can make these tables look like that:</p>
 | 
						|
<pre>
 | 
						|
    .----------------------.
 | 
						|
    | EMPLOYEE-COMPANY     |
 | 
						|
    `----------------------'
 | 
						|
    |  EMPLOYEE.ID         |
 | 
						|
    |  EMPLOYEE.COMPANY_ID |
 | 
						|
    |  EMPLOYEE.NAME       |
 | 
						|
    |  EMPLOYEE.SALARY     |
 | 
						|
    |  COMPANY.NAME        |
 | 
						|
    `----------------------'</pre>
 | 
						|
<p>The first thing that can be seen from there is that COMPANY.ID has disappeared
 | 
						|
from this ``Virtual'' table.</p>
 | 
						|
<p>Indeed, as for a given ``joined'' record this value must be the same in both
 | 
						|
tables, representing the values twice would have been a useless source of
 | 
						|
confusion.</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="select_statements">SELECT statements</a></h2>
 | 
						|
<p>Selecting from a Relation object is pretty simple using the GT::SQL module. As
 | 
						|
the interface is (almost) the same as <a href="glist.cgi?do=admin_gtdoc&topic=/GT/SQL/Table.html">the GT::SQL::Table manpage</a>, the GT::SQL wrapper
 | 
						|
returns Table or Relation objects depending on the arguments that are passed to
 | 
						|
table.</p>
 | 
						|
<pre>
 | 
						|
    # This gives me a GT::SQL::Table object for
 | 
						|
    # the EMPLOYEE table.
 | 
						|
    my $emp = $sql->table('EMPLOYEE');</pre>
 | 
						|
<pre>
 | 
						|
    # This gives me a GT::SQL::Relation object for
 | 
						|
    # the relation EMPLOYEE-COMPANY tables
 | 
						|
    my $emp_cmp = $sql->table('EMPLOYEE','COMPANY');</pre>
 | 
						|
<p>From there, performing a select is pretty simple:</p>
 | 
						|
<pre>
 | 
						|
    # select all the people from a real cool company
 | 
						|
    my $sth = $emp_cmp->select( { COMPANY.NAME => "Gossamer Threads" } )</pre>
 | 
						|
<p>Internally, the generated SQL query would look like:</p>
 | 
						|
<pre>
 | 
						|
    SELECT EMPLOYEE.ID, EMPLOYEE.COMPANY_ID, EMPLOYEE.NAME
 | 
						|
       EMPLOYEE.SALARY, COMPANY.NAME
 | 
						|
    FROM   EMPLOYEE, COMPANY
 | 
						|
    WHERE  COMPANY.NAME = 'Gossamer Threads' AND
 | 
						|
           EMPLOYEE.COMPANY_ID = COMPANY.ID</pre>
 | 
						|
<p>Note that the join condition is computed and automatically appended at the end
 | 
						|
of the query, so you do not have to worry about this.</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="select_options">SELECT options</a></h2>
 | 
						|
<p>The select options for relation are similar to that of table, you have
 | 
						|
<code>select_options()</code> which will be set for the next query done. Example:</p>
 | 
						|
<pre>
 | 
						|
    $relation->select_options("LIMIT 10");</pre>
 | 
						|
<p>This would append 'LIMIT 10' to your next select query.  Another useful thing
 | 
						|
is join_on(). <code>join_on()</code> allows you to specify the FK relation for the nextr
 | 
						|
select. This overrides what is in the def files. It is useful for allowing you
 | 
						|
to have one table which will be join differently depending on what you are
 | 
						|
doing. The argument to this are the same as to fk().
 | 
						|
Example:</p>
 | 
						|
<pre>
 | 
						|
    $relation->join_on( remote_table => { local_column => remote_column } );</pre>
 | 
						|
<p>The FK relation will be changed to this the next time you call <code>select()</code> but
 | 
						|
then it will be cleared.</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="listing_the_relation_columns">Listing the relation columns</a></h2>
 | 
						|
<p>* As previously said, the <code>cols()</code> method when invoked on a GT::SQL::Relation
 | 
						|
object does not return all the columns, removing the duplicate external
 | 
						|
references. So, how does it decides which column to keep and which one to
 | 
						|
return?</p>
 | 
						|
<p>In the EMPLOYEE-COMPANY example we have the constraint
 | 
						|
EMPLOYEE.COMPANY_ID => COMPANY.ID and it keeps COMPANY_ID, i.e. the foreign key
 | 
						|
instead of the key itself.</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="relation_primary_key">Relation primary key</a></h2>
 | 
						|
<p>* The <code>pk()</code> method has to return the table primary key. The property of a primary
 | 
						|
key is that it is a non-null unique record identifier.  When <code>pk()</code> is invoked on
 | 
						|
a Relation object, this base definition is applied to construct the object
 | 
						|
primary key.</p>
 | 
						|
<p>To find a unique set of fields that makes a good primary key for a Relation
 | 
						|
object, the following, simple algorithm is used:</p>
 | 
						|
<pre>
 | 
						|
    .                                                        .
 | 
						|
    . for each table                                         .
 | 
						|
    .   if the table is not referenced by another table that .
 | 
						|
    .   is in the current relation                           .
 | 
						|
    .     do                                                 .
 | 
						|
    .       append the current table's primary key fields to .
 | 
						|
    .       the Relation primary key fields                  .
 | 
						|
    .     end-do                                             .
 | 
						|
    .   end-if                                               .
 | 
						|
    . end-for                                                .
 | 
						|
    .                                                        .</pre>
 | 
						|
<p>This algorithm selects all the tables that represent the ``many'' in one-to-many
 | 
						|
relations, and for all these tables add a list of fields which ensure a record
 | 
						|
uniqueness.</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="foreign_keys_management">Foreign keys management</a></h2>
 | 
						|
<p>* When invoked on a GT::SQL::Table object, the <code>fk()</code> method returns a hash which
 | 
						|
has the following general structure:</p>
 | 
						|
<pre>
 | 
						|
    {
 | 
						|
      target_table_1 => {
 | 
						|
                          source_col_1 => target_col_1,
 | 
						|
                          source_col_2 => target_col_2
 | 
						|
                        },
 | 
						|
      target_table_2 => {
 | 
						|
                          source_col_1 => target_col_1
 | 
						|
            }
 | 
						|
    }</pre>
 | 
						|
<p>The GT::SQL::Relation module returns a hash which has the same structure. The
 | 
						|
only difference is that it does not returns the external references which are
 | 
						|
managed internally.</p>
 | 
						|
<p>This is done for two reasons: As one field is removed from a Relation table, it
 | 
						|
would not have been very logical to return a structure that point to
 | 
						|
non-existent fields.</p>
 | 
						|
<p>Moreover, these internal references from the ``Relation'' point of view have
 | 
						|
nothing to do with the external world and thus should not be shown.</p>
 | 
						|
<p>(i.e. EMPLOYEE.COMPANY_ID |===> COMPANY.ID would not count in our example)</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="inserting_data">Inserting data</a></h2>
 | 
						|
<p>The interface for inserting data in a Relation is the same as the one that is
 | 
						|
being used for Table. However, because rows are being inserted in a relation
 | 
						|
one-to-many, things internally work a bit differently.</p>
 | 
						|
<p>The Relation <code>insert()</code> method takes an optional argument, which can be
 | 
						|
'complete' or 'abort' (default being complete).</p>
 | 
						|
<p><code>insert()</code> splits the relation columns into separate records that can be inserted
 | 
						|
in a single table. However, some of the records may exist already!</p>
 | 
						|
<p>for example, if we perform:</p>
 | 
						|
<pre>
 | 
						|
    $sql = shift; # our GT::SQL object
 | 
						|
    $rel = $sql->table(qw/EMPLOYEE COMPANY/);
 | 
						|
    $rel->insert({
 | 
						|
        'EMPLOYEE.NAME'   => $your_name,
 | 
						|
        'EMPLOYEE.SALARY' => $big_buck,
 | 
						|
        'COMPANY.NAME'    => "Gossamer Threads"
 | 
						|
    });</pre>
 | 
						|
<p>Obviously the company ``Gossamer Threads'' already exists, but you were not in
 | 
						|
the ``EMPLOYEE'' table. Thus, when 'complete' is specified (it is the default
 | 
						|
option), the program will not complain if a record to insert already exists but
 | 
						|
just warns and continue the insertion work.</p>
 | 
						|
<p>In other words, Gossamer Threads exists already and it will not be inserted
 | 
						|
twice, but the employee will still be inserted and will belong to this company.</p>
 | 
						|
<p>On the other hand, if you specify ``abort'', then no data is inserted if a 
 | 
						|
record that has to be inserted would trigger an error in GT::SQL::Table.</p>
 | 
						|
<p>This feature can be useful if you want to insert a relation record assuming
 | 
						|
that none of the entities that you specify should exist.</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="deleting_data">Deleting data</a></h2>
 | 
						|
<p>Deleting data from a Relation object works using the following pattern:</p>
 | 
						|
<pre>
 | 
						|
    .                                                        .
 | 
						|
    . for each row that matches the delete condition         .
 | 
						|
    . do                                                     .
 | 
						|
    .   split the row in table-based records                 .
 | 
						|
    .   for each table that contains foreing keys from the   .
 | 
						|
    .       current relation object                          .
 | 
						|
    .   do                                                   .
 | 
						|
    .     delete the record                                  .
 | 
						|
    .   end-do                                               .
 | 
						|
    .                                                        .
 | 
						|
    .   for each table that is being referenced by another   .
 | 
						|
    .       table in the current relation object             .
 | 
						|
    .   do                                                   .
 | 
						|
    .     delete the record unless there exists              .
 | 
						|
    .     some "referencing" data.                           .
 | 
						|
    .   end-do                                               .
 | 
						|
    .                                                        .</pre>
 | 
						|
<p>As I feel that this explanation is probably very confusing, let us see how it
 | 
						|
works using our classical example (The salary column has been removed).</p>
 | 
						|
<pre>
 | 
						|
  .-------------------------------------------------------------.
 | 
						|
  | EMPLOYEE.ID | COMPANY_ID | EMPLOYEE.NAME | COMPANY.NAME     |
 | 
						|
  `-------------------------------------------------------------'
 | 
						|
  | 1           | 1          | Alex          | Gossamer Threads |
 | 
						|
  |-------------|------------|---------------|------------------|
 | 
						|
  | 2           | 1          | Scott         | Gossamer Threads |
 | 
						|
  |-------------|------------|---------------|------------------|
 | 
						|
  | 3           | 1          | Aki           | Gossamer Threads |
 | 
						|
  `-------------------------------------------------------------'</pre>
 | 
						|
<p>Now let us say that we do the following:</p>
 | 
						|
<pre>
 | 
						|
  # remove all the crazy geeks
 | 
						|
  $relation->delete({ 'EMPLOYEE.NAME' => 'Scott' });</pre>
 | 
						|
<p>This will remove ``Scott'' from the EMPLOYEE table, but of course
 | 
						|
Gossamer Threads will not be deleted because there still exists Alex and Aki
 | 
						|
that would reference it.</p>
 | 
						|
<p>Now if we do:</p>
 | 
						|
<pre>
 | 
						|
  $relation->delete({ 'COMPANY.NAME' => 'Gossamer Threads' });</pre>
 | 
						|
<p>or even</p>
 | 
						|
<pre>
 | 
						|
  my $condition = new GT::SQL::Condition;
 | 
						|
  $condition->add(qw/EMPLOYEE.NAME LIKE %/);
 | 
						|
  $relation->delete($condition);</pre>
 | 
						|
<p>Then we have generated a condition that matches all the employees, this means
 | 
						|
that when the last record will be deleted, then the company Gossamer Threads
 | 
						|
will have no more employees and therefore will be deleted.</p>
 | 
						|
<p>(Yeah, well, this is for the purpose of this example, of course this will never
 | 
						|
happen in real life :) )</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="updating_records">Updating records</a></h2>
 | 
						|
<p>Currently, there exists a limitation on updating records in a Relation, which
 | 
						|
is that only the records that represent the ``many'' part of the Relation are
 | 
						|
updated.</p>
 | 
						|
<p>The way it proceeds to perform the update is pretty simple:</p>
 | 
						|
<pre>
 | 
						|
    .                                                        .
 | 
						|
    . for each row that matches the update condition         .
 | 
						|
    . do                                                     .
 | 
						|
    .   split the row in table-based records                 .
 | 
						|
    .   for each table that contains foreing keys from the   .
 | 
						|
    .       current relation object                          .
 | 
						|
    .   do                                                   .
 | 
						|
    .     update the record                                  .
 | 
						|
    .   end-do                                               .
 | 
						|
    .                                                        .</pre>
 | 
						|
<p>That means that this will work:</p>
 | 
						|
<pre>
 | 
						|
  # SALARY being a property of EMPLOYEE, it will be updated
 | 
						|
  # because EMPLOYEE references COMPANY and therefore is a
 | 
						|
  # "many"
 | 
						|
  $relation->update({ SALARY => $big_bill },
 | 
						|
                    { 'COMPANY.NAME' => 'Gossamer Threads' });</pre>
 | 
						|
<pre>
 | 
						|
  # nope, you cannot use Relation to update the COMPANY table that
 | 
						|
  # way, this will not do anything.
 | 
						|
  $relation->update({ 'COMPANY.NAME' => 'New_Name' },
 | 
						|
                    { 'COMPANY.NAME' => 'Gossamer Threads' });</pre>
 | 
						|
<p>Who would like to change such a great name anyway ?</p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<h2><a name="selecting_records">Selecting Records</a></h2>
 | 
						|
<p>Select behaves exactly like <a href="glist.cgi?do=admin_gtdoc&topic=/GT/SQL/Table.html">the GT::SQL::Table manpage</a> select. The only difference is
 | 
						|
the ability to specify LEFT JOINs. For instance, if you want to see a list of
 | 
						|
Employees who don't belong to a company, you can do:</p>
 | 
						|
<pre>
 | 
						|
    my $relation = $DB->table('Employees', 'Company');
 | 
						|
    my $cond = GT::SQL::Condition->new('Company.ID', 'IS', \'NULL');
 | 
						|
    my $sth = $relation->select('left_join', $cond);</pre>
 | 
						|
<p>The order of tables specified in the relation constructor is important!</p>
 | 
						|
<p>In selecting columns, calling functions utilizing fully qualified column names
 | 
						|
will cause GT::SQL::Relation to fail. Simply turn the values into references
 | 
						|
like below.</p>
 | 
						|
<pre>
 | 
						|
    my $sth = $relation->select("MIN(Company.ID)"); # will fail</pre>
 | 
						|
<pre>
 | 
						|
    my $sth = $relation->select(\"MIN(Company.ID)"); # will work</pre>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<hr />
 | 
						|
<h1><a name="copyright">COPYRIGHT</a></h1>
 | 
						|
<p>Copyright (c) 2004 Gossamer Threads Inc.  All Rights Reserved.
 | 
						|
<a href="http://www.gossamer-threads.com/">http://www.gossamer-threads.com/</a></p>
 | 
						|
<p>
 | 
						|
</p>
 | 
						|
<hr />
 | 
						|
<h1><a name="version">VERSION</a></h1>
 | 
						|
<p>Revision: $Id: Relation.pm,v 1.102 2004/08/28 03:53:43 jagerman Exp $</p>
 | 
						|
 | 
						|
</body>
 | 
						|
 | 
						|
</html>
 |