This page demonstrates relational algebra by a simple interactive implementation. The algebra is loosely based on the ISBL language of PRTV, reworked in a javascript environment.

The page has three sections. The first shows the relations and operations. The second very briefly describes the interactive system and the relational language. The third gives some examples of error situations (in relational language use and in the implementation).

You may edit the expressions (green) see their results (blue).

r1 = R(['x','y'], [4, 7], [5, 9], [5, 4], [6, 7]) |
answer | initialization using selector followed by array values |

r2 = R( {x:4, z:"bill"}, {x:4, z:"bert"}, {x:5, z:"fred"} ) |
answer | initialization using Object values |

r1.join(r2) | answer |

r1.diff(r2) | answer |

r2.union(R({x:6, z:"fred"})) | answer |

r1.select("x == 4") | answer |

r1.project("x") | answer |

r1.rename("rr <- x") | answer |

r1.extend("c := x+4") | answer |

r1.extend("c := x+4, ~x") | answer |

r1.project("c := x+4") | answer |

r1.project("c := x+4, x") | answer |

r1.project("c := x+4, x == 5") | answer |

This implementation supports the two zero degree relations,
**{{}}** (true) which contains the empty tuple,
and **{}** (false) which is an empty relation.

The table form of HTML naturally generated for TABLE_DUM and TABLE_DEE are logically correctly different. However, (at least on Crome) they render identically on the page. The code therefore inserts the artificial "-" in TABLE_DEE so the empty tuple is visible.

It supports empty relations, but these are not typed. It is argued whether or not empty relations should be typed. I prefer typed empty relations; this implementation does not support them as that keeps the implementation as small as possible.

r1.select("x==7") | answer |

r1.diff(r1) | answer |

r1.project() | answer |

r1.select("x==7").project() | answer |

TABLE_DUM = R(); | answer |

TABLE_DEE = R({}); | answer |

This shows (embryonic) support for tuple expressions as variables.

tx=TX("c := x+4") | answer |

r1.extend(tx) | answer |

tx2 = tx.compose("x == 5") | answer |

r1.extend(tx2) | answer |

Nested relations are not fully implemented yet, but we are getting there ....

r3 = R({a:4, nest: r1}) | answer |

q=r1.group("x", "yg") | answer |

q=r1.group("", "xyg") | answer |

q=r1.group("x,y", "zerog") | answer |

// test here | answer |

You may edit the green values. Those are to the left of the blue results; the green is not very clear.

This is part of an experiment for a system that is a combination of 'active' html document editor, calculator and basic spreadsheet.
The green/blue pairs are javascript expressions and results.
This is not specific to relations; you can enter almost any valid javascript, including loop expressions etc.
Functions must be coded as **x = function() ...**, not as **function x()**,

A Relation is defined using R() in one of two javascript formats demonstrated above: either javascript Objects, or an array or arrays with the first element being the array of selectors. The operations on relations are:

- this.join(b)
- natural join of this with b
- this.diff(b)
- generalized difference of this with b
- this.extend(expr)
- extend using the string expression (see below)
- this.project(expr)
- project using the string expression (see below)
- this.rename(expr)
- same as extend (see below)
- this.select(expr)
- same as extend (see below)

Typing and error checking is incomplete and much later than it should be in a real system. Some examples of bad things are included below.

The EXTEND/PROJECT tuple expression is currently coded as a string, which is converted to a javascript function Tuple->Tuple. I may change the project later to use more properly structured expressions with cleaner semantics.

The tuple expression is a semicolon separated list of terms. Terms can include 'obvious' javascript, and are of the form

- x1 = x2
- The result of using javascript '=' is undefined (generally error)
- selector := jsexpression
- selector assignment to output tuple
- selector <- selector
- rename
- selector
- include this selector in the output (for project)
- ~selector
- remove this selector from the output (for extend)
- *
- copy all selector values from input to output tuple
- ~
- empty output tuple
- jsexpression
- javascript expression used as filter, usual javascript rules if it does not evaluate to a boolean (for filter)

Reference to a selector on the right hand side of the expression refers to the value of that selector in the output tuple if present, and to the value in the input tuple if not.

The only difference between EXTEND and PROJECT is that for EXTEND the output tuple is initialized to the input tuple, and for PROJECT the output tuple is initialized to the empty tuple. The two can be turned into each other by prefixing the expression with "*;" or "~;".

**rename** and **select** are included for syntactic reference, and are both identical to **extend**.
There are restrictions that could be put on pure expressions, this implementation does not enforce these.

- A pure rename would be limited to '<-' expression terms only.
- A pure projection would be limited to selector and '<-' expression terms only.
- A pure select would be limited to jsexpresssion filter terms.
- A pure extend would not allowed to use ~selector terms.

There are other restrictions that maybe should be applied but are not in this trivial code; for example := assignment should not be allowed to overwrite an already existing selector.

This section has some examples of wrong things.

- Some are wrong on the part of the queries asked, and get a correct (if obscure) error message.
- Some are wrong on the part of the queries asked, but the error is not caught and some sort of result is produced.
- Some are wrong in that the implementation just gets it wrong.

R({a:4}).union(R({b:5})) | answer |

R({a:4}).extend("~q") | answer |

R({a:4}).extend("a := a+4") | answer |

R({a:4}).extend("a := b+4") | answer |

R({a:"fred"}).extend("a := "re;ed") | answer |