@@ -20,14 +20,15 @@ TutorialD is strongly-typed. The basic built-in types are:
2020
2121|Type Name|Explanation|Example|
2222|---------|-----------|-------|
23−|text|arbitrary text|"The Old Man and the Sea"|
24−|int|any integer|-4|
25−|datetime|timestamp UTC|dateTimeFromEpochSeconds(1502304846)|
26−|date|calendar date|fromGregorian(2017,05,30)|
27−|double|floating point number|3.1459|
28−|bool|boolean value|t|
29−|bytestring|arbitrary-length string of bytes- input is base64-encoded|bytestring("dGVzdGRhdGE=")|
30−|interval x|interval/range type for ints, doubles, datetimes, and dates|interval(3,5,f,f)|
23+|Text|arbitrary text|"The Old Man and the Sea"|
24+|Integer|arbitarily-sized integer|-4|
25+|Int|machine word integer|int(10)|
26+|DateTime|timestamp UTC|dateTimeFromEpochSeconds(1502304846)|
27+|Date|calendar date|fromGregorian(2017,05,30)|
28+|Double|floating point number|3.1459|
29+|Bool|boolean value|t|
30+|Bytestring|arbitrary-length string of bytes- input is base64-encoded|bytestring("dGVzdGRhdGE=")|
31+|Interval x|interval/range type for ints, doubles, datetimes, and dates|interval(3,5,f,f)|
3132
3233With regards to boolean values, be sure not to conflate ```t``` or ```f``` as a boolean value with ```true``` and ```false``` which are relation variables.
3334
@@ -48,7 +49,7 @@ Relation Variables are named cells which reference relations within a transactio
4849
4950Definition of a relation variable:
5051```
51−products :: {name char, age int}
52+products :: {name Text, age Integer}
5253```
5354This expression creates a new relation variable in the current context which can refer to any relation with the header of "name" of type "char" and "age" of type int.
5455
@@ -151,15 +152,15 @@ The unary rename operator outputs a new relation with chosen attributes renamed.
151152
152153```
153154TutorialD (master/main): :showexpr s rename {city as town}
154−┌──┬─────┬──────┬──────┐
155−│s#│sname│status│town │
156−├──┼─────┼──────┼──────┤
157−│S3│Blake│30 │Paris │
158−│S4│Clark│20 │London│
159−│S5│Adams│30 │Athens│
160−│S1│Smith│20 │London│
161−│S2│Jones│10 │Paris │
162−└──┴─────┴──────┴──────┘
155+┌────────┬───────────┬───────────────┬──────────┐
156+│s#::Text│sname::Text│status::Integer│town::Text│
157+├────────┼───────────┼───────────────┼──────────┤
158+│"S3" │"Blake" │30 │"Paris" │
159+│"S4" │"Clark" │20 │"London" │
160+│"S5" │"Adams" │30 │"Athens" │
161+│"S1" │"Smith" │20 │"London" │
162+│"S2" │"Jones" │10 │"Paris" │
163+└────────┴───────────┴───────────────┴──────────┘
163164```
164165
165166#### Projection
@@ -170,14 +171,15 @@ For example:
170171
171172```
172173TutorialD (master/main): :showexpr p{color,city}
173−┌──────┬─────┐
174−│city │color│
175−├──────┼─────┤
176−│London│Red │
177−│Paris │Blue │
178−│Oslo │Blue │
179−│Paris │Green│
180−└──────┴─────┘
174+┌──────────┬───────────┐
175+│city::Text│color::Text│
176+├──────────┼───────────┤
177+│"London" │"Red" │
178+│"Paris" │"Green" │
179+│"Oslo" │"Blue" │
180+│"Paris" │"Blue" │
181+└──────────┴───────────┘
182+
181183```
182184
183185Projection attributes can also be inverted using `all but`:
@@ -217,22 +219,22 @@ Restriction is applied using a "where" clause, much like in SQL.
217219
218220```
219221TutorialD (master/main): :showexpr p where color="Blue" and city="Paris"
220−┌─────┬─────┬──┬─────┬──────┐
221−│city │color│p#│pname│weight│
222−├─────┼─────┼──┼─────┼──────┤
223−│Paris│Blue │P5│Cam │12 │
224−└─────┴─────┴──┴─────┴──────┘
222+┌──────────┬───────────┬────────┬───────────┬───────────────┐
223+│city::Text│color::Text│p#::Text│pname::Text│weight::Integer│
224+├──────────┼───────────┼────────┼───────────┼───────────────┤
225+│"Paris" │"Blue" │"P5" │"Cam" │12 │
226+└──────────┴───────────┴────────┴───────────┴───────────────┘
225227```
226228
227229The restriction predicate can be built from "and", "not", and "or". Boolean atom functions can also appear in a restriction as long as they are preceded by "^". For example:
228230
229231```
230232TutorialD (master/main): :showexpr s where ^lt(@status,20)
231−┌─────┬──┬─────┬──────┐
232−│city │s#│sname│status│
233−├─────┼──┼─────┼──────┤
234−│Paris│S2│Jones│10 │
235−└─────┴──┴─────┴──────┘
233+┌──────────┬────────┬───────────┬───────────────┐
234+│city::Text│s#::Text│sname::Text│status::Integer│
235+├──────────┼────────┼───────────┼───────────────┤
236+│"Paris" │"S2" │"Jones" │10 │
237+└──────────┴────────┴───────────┴───────────────┘
236238```
237239
238240#### Join
@@ -241,21 +243,22 @@ Joins are binary operators and are applied with the "join" keyword. The equivale
241243
242244```
243245TutorialD (master/main): :showexpr s join sp
244−┌──────┬──┬───┬──┬─────┬──────┐
245−│city │p#│QTY│s#│sname│status│
246−├──────┼──┼───┼──┼─────┼──────┤
247−│London│P6│100│S1│Smith│20 │
248−│London│P3│400│S1│Smith│20 │
249−│London│P5│400│S4│Clark│20 │
250−│London│P1│300│S1│Smith│20 │
251−│Paris │P2│200│S3│Blake│30 │
252−│Paris │P1│300│S2│Jones│10 │
253−│London│P5│100│S1│Smith│20 │
254−│London│P4│300│S4│Clark│20 │
255−│Paris │P2│400│S2│Jones│10 │
256−│London│P2│200│S1│Smith│20 │
257−│London│P4│200│S1│Smith│20 │
258−└──────┴──┴───┴──┴─────┴──────┘
246+┌──────────┬────────┬────────────┬────────┬───────────┬───────────────┐
247+│city::Text│p#::Text│qty::Integer│s#::Text│sname::Text│status::Integer│
248+├──────────┼────────┼────────────┼────────┼───────────┼───────────────┤
249+│"London" │"P2" │200 │"S1" │"Smith" │20 │
250+│"London" │"P6" │100 │"S1" │"Smith" │20 │
251+│"London" │"P3" │400 │"S1" │"Smith" │20 │
252+│"Paris" │"P2" │400 │"S2" │"Jones" │10 │
253+│"London" │"P5" │400 │"S4" │"Clark" │20 │
254+│"Paris" │"P1" │300 │"S2" │"Jones" │10 │
255+│"London" │"P1" │300 │"S1" │"Smith" │20 │
256+│"Paris" │"P2" │200 │"S3" │"Blake" │30 │
257+│"London" │"P4" │300 │"S4" │"Clark" │20 │
258+│"London" │"P2" │200 │"S4" │"Clark" │20 │
259+│"London" │"P4" │200 │"S1" │"Smith" │20 │
260+│"London" │"P5" │100 │"S1" │"Smith" │20 │
261+└──────────┴────────┴────────────┴────────┴───────────┴───────────────┘
259262```
260263
261264As a convenience, `tutd` also supports semijoin (`matching`) and antijoin (`not matching`) syntax.
@@ -269,16 +272,16 @@ As a convenience, `tutd` also supports semijoin (`matching`) and antijoin (`not
269272The binary union operator merges tuples from both relations if-and-only-if the attributes of both relations are identical. The SQL equivalent is the "UNION" operator. Unlike SQL, however, duplicate tuples are not tolerated, so there is no "UNION ALL" equivalent in the relational algebra.
270273
271274```
272−TutorialD (master/main): :showexpr S union S
273−┌──────┬──┬─────┬──────┐
274−│city │s#│sname│status│
275−├──────┼──┼─────┼──────┤
276−│Paris │S3│Blake│30 │
277−│London│S4│Clark│20 │
278−│Athens│S5│Adams│30 │
279−│London│S1│Smith│20 │
280−│Paris │S2│Jones│10 │
281−└──────┴──┴─────┴──────┘
275+TutorialD (master/main): :showexpr s union s
276+┌──────────┬────────┬───────────┬───────────────┐
277+│city::Text│s#::Text│sname::Text│status::Integer│
278+├──────────┼────────┼───────────┼───────────────┤
279+│"Paris" │"S3" │"Blake" │30 │
280+│"Athens" │"S5" │"Adams" │30 │
281+│"London" │"S1" │"Smith" │20 │
282+│"Paris" │"S2" │"Jones" │10 │
283+│"London" │"S4" │"Clark" │20 │
284+└──────────┴────────┴───────────┴───────────────┘
282285```
283286
284287The union of any relation with itself is itself.
@@ -289,15 +292,15 @@ The extend unary operator adds an attribute to a relation's header and body and
289292
290293```
291294TutorialD (master/main): :showexpr s:{status2:=add(10,@status)}
292−┌──────┬──┬─────┬──────┬───────┐
293−│city │s#│sname│status│status2│
294−├──────┼──┼─────┼──────┼───────┤
295−│Paris │S2│Jones│10 │20 │
296−│Athens│S5│Adams│30 │40 │
297−│Paris │S3│Blake│30 │40 │
298−│London│S1│Smith│20 │30 │
299−│London│S4│Clark│20 │30 │
300−└──────┴──┴─────┴──────┴───────┘
295+┌──────────┬────────┬───────────┬───────────────┬────────────────┐
296+│city::Text│s#::Text│sname::Text│status::Integer│status2::Integer│
297+├──────────┼────────┼───────────┼───────────────┼────────────────┤
298+│"Paris" │"S2" │"Jones" │10 │20 │
299+│"Athens" │"S5" │"Adams" │30 │40 │
300+│"London" │"S4" │"Clark" │20 │30 │
301+│"Paris" │"S3" │"Blake" │30 │40 │
302+│"London" │"S1" │"Smith" │20 │30 │
303+└──────────┴────────┴───────────┴───────────────┴────────────────┘
301304```
302305
303306The "@" is required in the above query in order to distinguish the attribute's name from a relation's name.
@@ -323,27 +326,27 @@ The group operator can also be used to emulate functionality similar to SQL's OU
323326
324327```
325328TutorialD (master/main): :showexpr s group ({sname,status,s#} as subrel)
326−┌──────┬─────────────────┐
327−│city │subrel │
328−├──────┼─────────────────┤
329−│Athens│┌──┬─────┬──────┐│
330−│ ││s#│sname│status││
331−│ │├──┼─────┼──────┤│
332−│ ││S5│Adams│30 ││
333−│ │└──┴─────┴──────┘│
334−│London│┌──┬─────┬──────┐│
335−│ ││s#│sname│status││
336−│ │├──┼─────┼──────┤│
337−│ ││S1│Smith│20 ││
338−│ ││S4│Clark│20 ││
339−│ │└──┴─────┴──────┘│
340−│Paris │┌──┬─────┬──────┐│
341−│ ││s#│sname│status││
342−│ │├──┼─────┼──────┤│
343−│ ││S3│Blake│30 ││
344−│ ││S2│Jones│10 ││
345−│ │└──┴─────┴──────┘│
346−└──────┴─────────────────┘
329+┌──────────┬───────────────────────────────────────────────────────┐
330+│city::Text│subrel::relation {s#::Text,sname::Text,status::Integer}│
331+├──────────┼───────────────────────────────────────────────────────┤
332+│"Athens" │┌────────┬───────────┬───────────────┐ │
333+│ ││s#::Text│sname::Text│status::Integer│ │
334+│ │├────────┼───────────┼───────────────┤ │
335+│ ││"S5" │"Adams" │30 │ │
336+│ │└────────┴───────────┴───────────────┘ │
337+│"Paris" │┌────────┬───────────┬───────────────┐ │
338+│ ││s#::Text│sname::Text│status::Integer│ │
339+│ │├────────┼───────────┼───────────────┤ │
340+│ ││"S2" │"Jones" │10 │ │
341+│ ││"S3" │"Blake" │30 │ │
342+│ │└────────┴───────────┴───────────────┘ │
343+│"London" │┌────────┬───────────┬───────────────┐ │
344+│ ││s#::Text│sname::Text│status::Integer│ │
345+│ │├────────┼───────────┼───────────────┤ │
346+│ ││"S4" │"Clark" │20 │ │
347+│ ││"S1" │"Smith" │20 │ │
348+│ │└────────┴───────────┴───────────────┘ │
349+└──────────┴───────────────────────────────────────────────────────┘
347350```
348351
349352#### Ungroup
@@ -352,15 +355,15 @@ The unary ungroup operator "unwraps" subrelations in a relation-valued attribute
352355
353356```
354357TutorialD (master/main): :showexpr (s group ({sname,status,s#} as subrel)) ungroup subrel
355−┌──────┬──┬─────┬──────┐
356−│city │s#│sname│status│
357−├──────┼──┼─────┼──────┤
358−│Paris │S3│Blake│30 │
359−│London│S4│Clark│20 │
360−│Athens│S5│Adams│30 │
361−│London│S1│Smith│20 │
362−│Paris │S2│Jones│10 │
363−└──────┴──┴─────┴──────┘
358+┌──────────┬────────┬───────────┬───────────────┐
359+│city::Text│s#::Text│sname::Text│status::Integer│
360+├──────────┼────────┼───────────┼───────────────┤
361+│"Paris" │"S2" │"Jones" │10 │
362+│"Paris" │"S3" │"Blake" │30 │
363+│"London" │"S4" │"Clark" │20 │
364+│"London" │"S1" │"Smith" │20 │
365+│"Athens" │"S5" │"Adams" │30 │
366+└──────────┴────────┴───────────┴───────────────┘
364367```
365368
366369#### Minus
@@ -393,11 +396,11 @@ The relation variable assignment mentioned above certainly changes the state of
393396```
394397TutorialD (master/main): newrelvar:=relation{tuple{age 3}}
395398TutorialD (master/main): :showexpr newrelvar
396−┌───┐
397−│age│
398−├───┤
399−│3 │
400−└───┘
399+┌────────────┐
400+│age::Integer│
401+├────────────┤
402+│3 │
403+└────────────┘
401404```
402405
403406All further operators are convenience operators and could be implemented with simple assignment. SQL has no equivalent to relational assignment; instead, one must issue "CREATE TABLE" commands and insert rows into the resultant tables.
@@ -419,16 +422,16 @@ The insert operators accepts a relation variable and a relation of the same type
419422```
420423TutorialD (master/main): insert s relation{tuple{city "Boston",s# "S10",sname "Gonzalez",status 10}}
421424TutorialD (master/main): :showexpr s
422−┌──────┬───┬────────┬──────┐
423−│city │s# │sname │status│
424−├──────┼───┼────────┼──────┤
425−│Paris │S3 │Blake │30 │
426−│London│S4 │Clark │20 │
427−│Athens│S5 │Adams │30 │
428−│London│S1 │Smith │20 │
429−│Paris │S2 │Jones │10 │
430−│Boston│S10│Gonzalez│10 │
431−└──────┴───┴────────┴──────┘
425+┌──────────┬────────┬───────────┬───────────────┐
426+│city::Text│s#::Text│sname::Text│status::Integer│
427+├──────────┼────────┼───────────┼───────────────┤
428+│"Athens" │"S5" │"Adams" │30 │
429+│"Paris" │"S2" │"Jones" │10 │
430+│"Boston" │"S10" │"Gonzalez" │10 │
431+│"London" │"S4" │"Clark" │20 │
432+│"London" │"S1" │"Smith" │20 │
433+│"Paris" │"S3" │"Blake" │30 │
434+└──────────┴────────┴───────────┴───────────────┘
432435```
433436
434437This insertion operation is equivalent to:
@@ -443,15 +446,15 @@ The update operator accepts a relation argument and a predicate, optionally filt
443446```
444447TutorialD (master/main): update s where status=20 (sname:="Mr. Twenty")
445448TutorialD (master/main): :showexpr s
446−┌──────┬──┬──────────┬──────┐
447−│city │s#│sname │status│
448−├──────┼──┼──────────┼──────┤
449−│Paris │S3│Blake │30 │
450−│London│S1│Mr. Twenty│20 │
451−│Athens│S5│Adams │30 │
452−│Paris │S2│Jones │10 │
453−│London│S4│Mr. Twenty│20 │
454−└──────┴──┴──────────┴──────┘
449+┌──────────┬────────┬────────────┬───────────────┐
450+│city::Text│s#::Text│sname::Text │status::Integer│
451+├──────────┼────────┼────────────┼───────────────┤
452+│"Paris" │"S2" │"Jones" │10 │
453+│"London" │"S1" │"Mr. Twenty"│20 │
454+│"Paris" │"S3" │"Blake" │30 │
455+│"London" │"S4" │"Mr. Twenty"│20 │
456+│"Athens" │"S5" │"Adams" │30 │
457+└──────────┴────────┴────────────┴───────────────┘
455458```
456459
457460This is logically equivalent to:
@@ -459,15 +462,15 @@ This is logically equivalent to:
459462```
460463TutorialD (master/main): s:=(((s where status=20){city,s#,status}):{sname:="Mr. Twenty"}) union (s where not status=20)
461464TutorialD (master/main): :showexpr s
462−┌──────┬──┬──────────┬──────┐
463−│city │s#│sname │status│
464−├──────┼──┼──────────┼──────┤
465−│Paris │S3│Blake │30 │
466−│London│S1│Mr. Twenty│20 │
467−│Athens│S5│Adams │30 │
468−│Paris │S2│Jones │10 │
469−│London│S4│Mr. Twenty│20 │
470−└──────┴──┴──────────┴──────┘
465+┌──────────┬────────┬────────────┬───────────────┐
466+│city::Text│s#::Text│sname::Text │status::Integer│
467+├──────────┼────────┼────────────┼───────────────┤
468+│"Paris" │"S2" │"Jones" │10 │
469+│"London" │"S1" │"Mr. Twenty"│20 │
470+│"Paris" │"S3" │"Blake" │30 │
471+│"London" │"S4" │"Mr. Twenty"│20 │
472+│"Athens" │"S5" │"Adams" │30 │
473+└──────────┴────────┴────────────┴───────────────┘
471474```
472475
473476This query means: "Drop the sname attribute from S filtered where status equals 20, extend the resultant relation by sname with value 'Mr. Twenty', then union the resultant relation with S filtered by status not equaling 20, and assign that to S."
@@ -479,19 +482,19 @@ The delete operator accepts a relation argument and a filtering predicate, creat
479482```
480483TutorialD (master/main): delete sp where s#="S4"
481484TutorialD (master/main): :showexpr sp
482−┌──┬───┬──┐
483−│p#│QTY│s#│
484−├──┼───┼──┤
485−│P3│400│S1│
486−│P4│200│S1│
487−│P2│400│S2│
488−│P2│200│S1│
489−│P6│100│S1│
490−│P1│300│S1│
491−│P2│200│S3│
492−│P1│300│S2│
493−│P5│100│S1│
494−└──┴───┴──┘
485+┌────────┬────────────┬────────┐
486+│p#::Text│qty::Integer│s#::Text│
487+├────────┼────────────┼────────┤
488+│"P2" │200 │"S3" │
489+│"P2" │400 │"S2" │
490+│"P1" │300 │"S1" │
491+│"P5" │100 │"S1" │
492+│"P4" │200 │"S1" │
493+│"P1" │300 │"S2" │
494+│"P3" │400 │"S1" │
495+│"P2" │200 │"S1" │
496+│"P6" │100 │"S1" │
497+└────────┴────────────┴────────┘
495498```
496499
497500This is logically equivalent to:
@@ -526,7 +529,7 @@ Foreign keys are constraints which require that certain values appearing in one
526529TutorialD (master/main): foreign key s#_in_sp sp{s#} in s{s#}
527530```
528531
529−This expression ensure that any sp{s#} must also appear as a value in s{s#}. Note that the sub-expression (on the left of "in") and the super-expression (on the right) must be of the same relation type- the generated relation values' attribute names and types must be equal. Use `rename` to make attribute names identical.
532+This expression ensure that any sp{s#} must also appear as a value in s{s#}. Note that the sub-expression (on the left of "in") and the super-expression (on the right) must be of the same relation type- the generated relation values' attribute names and types must be equal. Use `rename` to make attribute names identical.
530533
531534#### Functional dependencies
532535
@@ -560,27 +563,27 @@ SQL supports aggregate queries using aggregate functions (SUM(), COUNT(), AVERAG
560563
561564```
562565TutorialD (master/main): :showexpr s group ({s#,sname,status} as subrel):{citycount:=count(@subrel)}
563−┌──────┬─────────┬─────────────────┐
564−│city │citycount│subrel │
565−├──────┼─────────┼─────────────────┤
566−│Paris │2 │┌──┬─────┬──────┐│
567−│ │ ││s#│sname│status││
568−│ │ │├──┼─────┼──────┤│
569−│ │ ││S3│Blake│30 ││
570−│ │ ││S2│Jones│10 ││
571−│ │ │└──┴─────┴──────┘│
572−│London│2 │┌──┬─────┬──────┐│
573−│ │ ││s#│sname│status││
574−│ │ │├──┼─────┼──────┤│
575−│ │ ││S1│Smith│20 ││
576−│ │ ││S4│Clark│20 ││
577−│ │ │└──┴─────┴──────┘│
578−│Athens│1 │┌──┬─────┬──────┐│
579−│ │ ││s#│sname│status││
580−│ │ │├──┼─────┼──────┤│
581−│ │ ││S5│Adams│30 ││
582−│ │ │└──┴─────┴──────┘│
583−└──────┴─────────┴─────────────────┘
566+┌──────────┬──────────────────┬───────────────────────────────────────────────────────┐
567+│city::Text│citycount::Integer│subrel::relation {s#::Text,sname::Text,status::Integer}│
568+├──────────┼──────────────────┼───────────────────────────────────────────────────────┤
569+│"Athens" │1 │┌────────┬───────────┬───────────────┐ │
570+│ │ ││s#::Text│sname::Text│status::Integer│ │
571+│ │ │├────────┼───────────┼───────────────┤ │
572+│ │ ││"S5" │"Adams" │30 │ │
573+│ │ │└────────┴───────────┴───────────────┘ │
574+│"Paris" │2 │┌────────┬───────────┬───────────────┐ │
575+│ │ ││s#::Text│sname::Text│status::Integer│ │
576+│ │ │├────────┼───────────┼───────────────┤ │
577+│ │ ││"S2" │"Jones" │10 │ │
578+│ │ ││"S3" │"Blake" │30 │ │
579+│ │ │└────────┴───────────┴───────────────┘ │
580+│"London" │2 │┌────────┬───────────┬───────────────┐ │
581+│ │ ││s#::Text│sname::Text│status::Integer│ │
582+│ │ │├────────┼───────────┼───────────────┤ │
583+│ │ ││"S4" │"Clark" │20 │ │
584+│ │ ││"S1" │"Smith" │20 │ │
585+│ │ │└────────┴───────────┴───────────────┘ │
586+└──────────┴──────────────────┴───────────────────────────────────────────────────────┘
584587```
585588
586589In this query result, we can simultaneously answer how many suppliers are located in each city and which suppliers they are. The expression is constructed by first grouping to isolate the city, then extending the query to add a attribute containing the tuple count for each subrelation.