on master help sign in
update TutorialD tutorial to include latest type-related changes
0a73890AgentM
docs/tutd_tutorial.markdown+171−168
@@ -20,14 +20,15 @@ TutorialD is strongly-typed. The basic built-in types are:
20
20
21|Type Name|Explanation|Example|
21|Type Name|Explanation|Example|
22|---------|-----------|-------|
22|---------|-----------|-------|
23−|text|arbitrary text|"The Old Man and the Sea"|
23+|Text|arbitrary text|"The Old Man and the Sea"|
24−|int|any integer|-4|
24+|Integer|arbitarily-sized integer|-4|
25+|Int|machine word integer|int(10)|
25−|datetime|timestamp UTC|dateTimeFromEpochSeconds(1502304846)|
26+|DateTime|timestamp UTC|dateTimeFromEpochSeconds(1502304846)|
26−|date|calendar date|fromGregorian(2017,05,30)|
27+|Date|calendar date|fromGregorian(2017,05,30)|
27−|double|floating point number|3.1459|
28+|Double|floating point number|3.1459|
28−|bool|boolean value|t|
29+|Bool|boolean value|t|
29−|bytestring|arbitrary-length string of bytes- input is base64-encoded|bytestring("dGVzdGRhdGE=")|
30+|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)|
31+|Interval x|interval/range type for ints, doubles, datetimes, and dates|interval(3,5,f,f)|
31
32
32With regards to boolean values, be sure not to conflate ```t``` or ```f``` as a boolean value with ```true``` and ```false``` which are relation variables.
33With regards to boolean values, be sure not to conflate ```t``` or ```f``` as a boolean value with ```true``` and ```false``` which are relation variables.
33
34
@@ -48,7 +49,7 @@ Relation Variables are named cells which reference relations within a transactio
48
49
49Definition of a relation variable:
50Definition of a relation variable:
50```
51```
51−products :: {name char, age int}
52+products :: {name Text, age Integer}
52```
53```
53This 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.
54This 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.
54
55
@@ -151,15 +152,15 @@ The unary rename operator outputs a new relation with chosen attributes renamed.
151
152
152```
153```
153TutorialD (master/main): :showexpr s rename {city as town}
154TutorialD (master/main): :showexpr s rename {city as town}
154−┌──┬─────┬──────┬──────┐
155+┌────────┬───────────┬───────────────┬──────────┐
155−│s#│sname│status│town │
156+│s#::Text│sname::Text│status::Integer│town::Text│
156−├──┼─────┼──────┼──────┤
157+├────────┼───────────┼───────────────┼──────────┤
157−│S3│Blake│30 │Paris │
158+│"S3" │"Blake" │30 │"Paris" │
158−│S4│Clark│20 │London│
159+│"S4" │"Clark" │20 │"London" │
159−│S5│Adams│30 │Athens│
160+│"S5" │"Adams" │30 │"Athens" │
160−│S1│Smith│20 │London│
161+│"S1" │"Smith" │20 │"London" │
161−│S2│Jones│10 │Paris │
162+│"S2" │"Jones" │10 │"Paris" │
162−└──┴─────┴──────┴──────┘
163+└────────┴───────────┴───────────────┴──────────┘
163```
164```
164
165
165#### Projection
166#### Projection
@@ -170,14 +171,15 @@ For example:
170
171
171```
172```
172TutorialD (master/main): :showexpr p{color,city}
173TutorialD (master/main): :showexpr p{color,city}
173−┌──────┬─────┐
174+┌──────────┬───────────┐
174−│city │color│
175+│city::Text│color::Text│
175−├──────┼─────┤
176+├──────────┼───────────┤
176−│London│Red │
177+│"London" │"Red" │
177−│Paris │Blue │
178+│"Paris" │"Green" │
178−│Oslo │Blue │
179+│"Oslo" │"Blue" │
179−│Paris │Green│
180+│"Paris" │"Blue" │
180−└──────┴─────┘
181+└──────────┴───────────┘
182+
181```
183```
182
184
183Projection attributes can also be inverted using `all but`:
185Projection attributes can also be inverted using `all but`:
@@ -217,22 +219,22 @@ Restriction is applied using a "where" clause, much like in SQL.
217
219
218```
220```
219TutorialD (master/main): :showexpr p where color="Blue" and city="Paris"
221TutorialD (master/main): :showexpr p where color="Blue" and city="Paris"
220−┌─────┬─────┬──┬─────┬──────┐
222+┌──────────┬───────────┬────────┬───────────┬───────────────┐
221−│city │color│p#│pname│weight│
223+│city::Text│color::Text│p#::Text│pname::Text│weight::Integer│
222−├─────┼─────┼──┼─────┼──────┤
224+├──────────┼───────────┼────────┼───────────┼───────────────┤
223−│Paris│Blue │P5│Cam │12 │
225+│"Paris" │"Blue" │"P5" │"Cam" │12 │
224−└─────┴─────┴──┴─────┴──────┘
226+└──────────┴───────────┴────────┴───────────┴───────────────┘
225```
227```
226
228
227The 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:
229The 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:
228
230
229```
231```
230TutorialD (master/main): :showexpr s where ^lt(@status,20)
232TutorialD (master/main): :showexpr s where ^lt(@status,20)
231−┌─────┬──┬─────┬──────┐
233+┌──────────┬────────┬───────────┬───────────────┐
232−│city │s#│sname│status│
234+│city::Text│s#::Text│sname::Text│status::Integer│
233−├─────┼──┼─────┼──────┤
235+├──────────┼────────┼───────────┼───────────────┤
234−│Paris│S2│Jones│10 │
236+│"Paris" │"S2" │"Jones" │10 │
235−└─────┴──┴─────┴──────┘
237+└──────────┴────────┴───────────┴───────────────┘
236```
238```
237
239
238#### Join
240#### Join
@@ -241,21 +243,22 @@ Joins are binary operators and are applied with the "join" keyword. The equivale
241
243
242```
244```
243TutorialD (master/main): :showexpr s join sp
245TutorialD (master/main): :showexpr s join sp
244−┌──────┬──┬───┬──┬─────┬──────┐
246+┌──────────┬────────┬────────────┬────────┬───────────┬───────────────┐
245−│city │p#│QTY│s#│sname│status│
247+│city::Text│p#::Text│qty::Integer│s#::Text│sname::Text│status::Integer│
246−├──────┼──┼───┼──┼─────┼──────┤
248+├──────────┼────────┼────────────┼────────┼───────────┼───────────────┤
249+│"London" │"P2" │200 │"S1" │"Smith" │20 │
247−│London│P6│100│S1│Smith│20 │
250+│"London" │"P6" │100 │"S1" │"Smith" │20 │
248−│London│P3│400│S1│Smith│20 │
251+│"London" │"P3" │400 │"S1" │"Smith" │20 │
252+│"Paris" │"P2" │400 │"S2" │"Jones" │10 │
249−│London│P5│400│S4│Clark│20 │
253+│"London" │"P5" │400 │"S4" │"Clark" │20 │
254+│"Paris" │"P1" │300 │"S2" │"Jones" │10 │
250−│London│P1│300│S1│Smith│20 │
255+│"London" │"P1" │300 │"S1" │"Smith" │20 │
251−│Paris │P2│200│S3│Blake│30 │
256+│"Paris" │"P2" │200 │"S3" │"Blake" │30 │
252−│Paris │P1│300│S2│Jones│10 │
257+│"London" │"P4" │300 │"S4" │"Clark" │20 │
253−│London│P5│100│S1│Smith│20 │
254−│London│P4│300│S4│Clark│20 │
258+│"London" │"P2" │200 │"S4" │"Clark" │20 │
255−│Paris │P2│400│S2│Jones│10 │
256−│London│P2│200│S1│Smith│20 │
259+│"London" │"P4" │200 │"S1" │"Smith" │20 │
257−│London│P4│200│S1│Smith│20 │
260+│"London" │"P5" │100 │"S1" │"Smith" │20 │
258−└──────┴──┴───┴──┴─────┴──────┘
261+└──────────┴────────┴────────────┴────────┴───────────┴───────────────┘
259```
262```
260
263
261As a convenience, `tutd` also supports semijoin (`matching`) and antijoin (`not matching`) syntax.
264As 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
269The 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.
272The 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.
270
273
271```
274```
272−TutorialD (master/main): :showexpr S union S
275+TutorialD (master/main): :showexpr s union s
273−┌──────┬──┬─────┬──────┐
276+┌──────────┬────────┬───────────┬───────────────┐
274−│city │s#│sname│status│
277+│city::Text│s#::Text│sname::Text│status::Integer│
275−├──────┼──┼─────┼──────┤
278+├──────────┼────────┼───────────┼───────────────┤
276−│Paris │S3│Blake│30 │
279+│"Paris" │"S3" │"Blake" │30 │
277−│London│S4│Clark│20 │
278−│Athens│S5│Adams│30 │
280+│"Athens" │"S5" │"Adams" │30 │
279−│London│S1│Smith│20 │
281+│"London" │"S1" │"Smith" │20 │
280−│Paris │S2│Jones│10 │
282+│"Paris" │"S2" │"Jones" │10 │
283+│"London" │"S4" │"Clark" │20 │
281−└──────┴──┴─────┴──────┘
284+└──────────┴────────┴───────────┴───────────────┘
282```
285```
283
286
284The union of any relation with itself is itself.
287The 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
289
292
290```
293```
291TutorialD (master/main): :showexpr s:{status2:=add(10,@status)}
294TutorialD (master/main): :showexpr s:{status2:=add(10,@status)}
292−┌──────┬──┬─────┬──────┬───────┐
295+┌──────────┬────────┬───────────┬───────────────┬────────────────┐
293−│city │s#│sname│status│status2│
296+│city::Text│s#::Text│sname::Text│status::Integer│status2::Integer│
294−├──────┼──┼─────┼──────┼───────┤
297+├──────────┼────────┼───────────┼───────────────┼────────────────┤
295−│Paris │S2│Jones│10 │20 │
298+│"Paris" │"S2" │"Jones" │10 │20 │
296−│Athens│S5│Adams│30 │40 │
299+│"Athens" │"S5" │"Adams" │30 │40 │
300+│"London" │"S4" │"Clark" │20 │30 │
297−│Paris │S3│Blake│30 │40 │
301+│"Paris" │"S3" │"Blake" │30 │40 │
298−│London│S1│Smith│20 │30 │
302+│"London" │"S1" │"Smith" │20 │30 │
299−│London│S4│Clark│20 │30 │
300−└──────┴──┴─────┴──────┴───────┘
303+└──────────┴────────┴───────────┴───────────────┴────────────────┘
301```
304```
302
305
303The "@" is required in the above query in order to distinguish the attribute's name from a relation's name.
306The "@" 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
323
326
324```
327```
325TutorialD (master/main): :showexpr s group ({sname,status,s#} as subrel)
328TutorialD (master/main): :showexpr s group ({sname,status,s#} as subrel)
326−┌──────┬─────────────────┐
329+┌──────────┬───────────────────────────────────────────────────────┐
327−│city │subrel │
330+│city::Text│subrel::relation {s#::Text,sname::Text,status::Integer}│
328−├──────┼─────────────────┤
331+├──────────┼───────────────────────────────────────────────────────┤
329−│Athens│┌──┬─────┬──────┐│
332+│"Athens" │┌────────┬───────────┬───────────────┐ │
330−│ ││s#│sname│status││
333+│ ││s#::Text│sname::Text│status::Integer│ │
331−│ │├──┼─────┼──────┤│
334+│ │├────────┼───────────┼───────────────┤ │
332−│ ││S5│Adams│30 ││
335+│ ││"S5" │"Adams" │30 │ │
333−│ │└──┴─────┴──────┘│
334−│London│┌──┬─────┬──────┐│
335−│ ││s#│sname│status││
336−│ │├──┼─────┼──────┤│
337−│ ││S1│Smith│20 ││
338−│ ││S4│Clark│20 ││
339−│ │└──┴─────┴──────┘│
336+│ │└────────┴───────────┴───────────────┘ │
340−│Paris │┌──┬─────┬──────┐│
337+│"Paris" │┌────────┬───────────┬───────────────┐ │
341−│ ││s#│sname│status││
338+│ ││s#::Text│sname::Text│status::Integer│ │
342−│ │├──┼─────┼──────┤│
339+│ │├────────┼───────────┼───────────────┤ │
343−│ ││S3│Blake│30 ││
344−│ ││S2│Jones│10 ││
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 │ │
345−│ │└──┴─────┴──────┘│
348+│ │└────────┴───────────┴───────────────┘ │
346−└──────┴─────────────────┘
349+└──────────┴───────────────────────────────────────────────────────┘
347```
350```
348
351
349#### Ungroup
352#### Ungroup
@@ -352,15 +355,15 @@ The unary ungroup operator "unwraps" subrelations in a relation-valued attribute
352
355
353```
356```
354TutorialD (master/main): :showexpr (s group ({sname,status,s#} as subrel)) ungroup subrel
357TutorialD (master/main): :showexpr (s group ({sname,status,s#} as subrel)) ungroup subrel
355−┌──────┬──┬─────┬──────┐
358+┌──────────┬────────┬───────────┬───────────────┐
356−│city │s#│sname│status│
359+│city::Text│s#::Text│sname::Text│status::Integer│
357−├──────┼──┼─────┼──────┤
360+├──────────┼────────┼───────────┼───────────────┤
361+│"Paris" │"S2" │"Jones" │10 │
358−│Paris │S3│Blake│30 │
362+│"Paris" │"S3" │"Blake" │30 │
359−│London│S4│Clark│20 │
363+│"London" │"S4" │"Clark" │20 │
364+│"London" │"S1" │"Smith" │20 │
360−│Athens│S5│Adams│30 │
365+│"Athens" │"S5" │"Adams" │30 │
361−│London│S1│Smith│20 │
362−│Paris │S2│Jones│10 │
363−└──────┴──┴─────┴──────┘
366+└──────────┴────────┴───────────┴───────────────┘
364```
367```
365
368
366#### Minus
369#### Minus
@@ -393,11 +396,11 @@ The relation variable assignment mentioned above certainly changes the state of
393```
396```
394TutorialD (master/main): newrelvar:=relation{tuple{age 3}}
397TutorialD (master/main): newrelvar:=relation{tuple{age 3}}
395TutorialD (master/main): :showexpr newrelvar
398TutorialD (master/main): :showexpr newrelvar
396−┌───┐
399+┌────────────┐
397−│age│
400+│age::Integer│
398−├───┤
401+├────────────┤
399−│3 │
402+│3 │
400−└───┘
403+└────────────┘
401```
404```
402
405
403All 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.
406All 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
419```
422```
420TutorialD (master/main): insert s relation{tuple{city "Boston",s# "S10",sname "Gonzalez",status 10}}
423TutorialD (master/main): insert s relation{tuple{city "Boston",s# "S10",sname "Gonzalez",status 10}}
421TutorialD (master/main): :showexpr s
424TutorialD (master/main): :showexpr s
422−┌──────┬───┬────────┬──────┐
425+┌──────────┬────────┬───────────┬───────────────┐
423−│city │s# │sname │status│
426+│city::Text│s#::Text│sname::Text│status::Integer│
424−├──────┼───┼────────┼──────┤
427+├──────────┼────────┼───────────┼───────────────┤
425−│Paris │S3 │Blake │30 │
426−│London│S4 │Clark │20 │
427−│Athens│S5 │Adams │30 │
428+│"Athens" │"S5" │"Adams" │30 │
428−│London│S1 │Smith │20 │
429−│Paris │S2 │Jones │10 │
429+│"Paris" │"S2" │"Jones" │10 │
430−│Boston│S10│Gonzalez│10 │
430+│"Boston" │"S10" │"Gonzalez" │10 │
431+│"London" │"S4" │"Clark" │20 │
432+│"London" │"S1" │"Smith" │20 │
433+│"Paris" │"S3" │"Blake" │30 │
431−└──────┴───┴────────┴──────┘
434+└──────────┴────────┴───────────┴───────────────┘
432```
435```
433
436
434This insertion operation is equivalent to:
437This insertion operation is equivalent to:
@@ -443,15 +446,15 @@ The update operator accepts a relation argument and a predicate, optionally filt
443```
446```
444TutorialD (master/main): update s where status=20 (sname:="Mr. Twenty")
447TutorialD (master/main): update s where status=20 (sname:="Mr. Twenty")
445TutorialD (master/main): :showexpr s
448TutorialD (master/main): :showexpr s
446−┌──────┬──┬──────────┬──────┐
449+┌──────────┬────────┬────────────┬───────────────┐
447−│city │s#│sname │status│
450+│city::Text│s#::Text│sname::Text │status::Integer│
448−├──────┼──┼──────────┼──────┤
451+├──────────┼────────┼────────────┼───────────────┤
452+│"Paris" │"S2" │"Jones" │10 │
453+│"London" │"S1" │"Mr. Twenty"│20 │
449−│Paris │S3│Blake │30 │
454+│"Paris" │"S3" │"Blake" │30 │
450−│London│S1│Mr. Twenty│20 │
455+│"London" │"S4" │"Mr. Twenty"│20 │
451−│Athens│S5│Adams │30 │
456+│"Athens" │"S5" │"Adams" │30 │
452−│Paris │S2│Jones │10 │
453−│London│S4│Mr. Twenty│20 │
454−└──────┴──┴──────────┴──────┘
457+└──────────┴────────┴────────────┴───────────────┘
455```
458```
456
459
457This is logically equivalent to:
460This is logically equivalent to:
@@ -459,15 +462,15 @@ This is logically equivalent to:
459```
462```
460TutorialD (master/main): s:=(((s where status=20){city,s#,status}):{sname:="Mr. Twenty"}) union (s where not status=20)
463TutorialD (master/main): s:=(((s where status=20){city,s#,status}):{sname:="Mr. Twenty"}) union (s where not status=20)
461TutorialD (master/main): :showexpr s
464TutorialD (master/main): :showexpr s
462−┌──────┬──┬──────────┬──────┐
465+┌──────────┬────────┬────────────┬───────────────┐
463−│city │s#│sname │status│
466+│city::Text│s#::Text│sname::Text │status::Integer│
464−├──────┼──┼──────────┼──────┤
467+├──────────┼────────┼────────────┼───────────────┤
468+│"Paris" │"S2" │"Jones" │10 │
469+│"London" │"S1" │"Mr. Twenty"│20 │
465−│Paris │S3│Blake │30 │
470+│"Paris" │"S3" │"Blake" │30 │
466−│London│S1│Mr. Twenty│20 │
471+│"London" │"S4" │"Mr. Twenty"│20 │
467−│Athens│S5│Adams │30 │
472+│"Athens" │"S5" │"Adams" │30 │
468−│Paris │S2│Jones │10 │
469−│London│S4│Mr. Twenty│20 │
470−└──────┴──┴──────────┴──────┘
473+└──────────┴────────┴────────────┴───────────────┘
471```
474```
472
475
473This 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."
476This 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
479```
482```
480TutorialD (master/main): delete sp where s#="S4"
483TutorialD (master/main): delete sp where s#="S4"
481TutorialD (master/main): :showexpr sp
484TutorialD (master/main): :showexpr sp
482−┌──┬───┬──┐
485+┌────────┬────────────┬────────┐
483−│p#│QTY│s#│
486+│p#::Text│qty::Integer│s#::Text│
484−├──┼───┼──┤
487+├────────┼────────────┼────────┤
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│
488+│"P2" │200 │"S3" │
489+│"P2" │400 │"S2" │
492−│P1│300│S2│
490+│"P1" │300 │"S1" │
493−│P5│100│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" │
494−└──┴───┴──┘
497+└────────┴────────────┴────────┘
495```
498```
496
499
497This is logically equivalent to:
500This is logically equivalent to:
@@ -526,7 +529,7 @@ Foreign keys are constraints which require that certain values appearing in one
526TutorialD (master/main): foreign key s#_in_sp sp{s#} in s{s#}
529TutorialD (master/main): foreign key s#_in_sp sp{s#} in s{s#}
527```
530```
528
531
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.
530
533
531#### Functional dependencies
534#### Functional dependencies
532
535
@@ -560,27 +563,27 @@ SQL supports aggregate queries using aggregate functions (SUM(), COUNT(), AVERAG
560
563
561```
564```
562TutorialD (master/main): :showexpr s group ({s#,sname,status} as subrel):{citycount:=count(@subrel)}
565TutorialD (master/main): :showexpr s group ({s#,sname,status} as subrel):{citycount:=count(@subrel)}
563−┌──────┬─────────┬─────────────────┐
566+┌──────────┬──────────────────┬───────────────────────────────────────────────────────┐
564−│city │citycount│subrel │
567+│city::Text│citycount::Integer│subrel::relation {s#::Text,sname::Text,status::Integer}│
568+├──────────┼──────────────────┼───────────────────────────────────────────────────────┤
569+│"Athens" │1 │┌────────┬───────────┬───────────────┐ │
570+│ │ ││s#::Text│sname::Text│status::Integer│ │
565−├──────┼─────────┼─────────────────┤
571+│ │ │├────────┼───────────┼───────────────┤ │
572+│ │ ││"S5" │"Adams" │30 │ │
573+│ │ │└────────┴───────────┴───────────────┘ │
566−│Paris │2 │┌──┬─────┬──────┐│
574+│"Paris" │2 │┌────────┬───────────┬───────────────┐ │
567−│ │ ││s#│sname│status││
575+│ │ ││s#::Text│sname::Text│status::Integer│ │
568−│ │ │├──┼─────┼──────┤│
576+│ │ │├────────┼───────────┼───────────────┤ │
569−│ │ ││S3│Blake│30 ││
570−│ │ ││S2│Jones│10 ││
577+│ │ ││"S2" │"Jones" │10 │ │
578+│ │ ││"S3" │"Blake" │30 │ │
571−│ │ │└──┴─────┴──────┘│
579+│ │ │└────────┴───────────┴───────────────┘ │
572−│London│2 │┌──┬─────┬──────┐│
580+│"London" │2 │┌────────┬───────────┬───────────────┐ │
573−│ │ ││s#│sname│status││
581+│ │ ││s#::Text│sname::Text│status::Integer│ │
574−│ │ │├──┼─────┼──────┤│
582+│ │ │├────────┼───────────┼───────────────┤ │
583+│ │ ││"S4" │"Clark" │20 │ │
575−│ │ ││S1│Smith│20 ││
584+│ │ ││"S1" │"Smith" │20 │ │
576−│ │ ││S4│Clark│20 ││
577−│ │ │└──┴─────┴──────┘│
585+│ │ │└────────┴───────────┴───────────────┘ │
578−│Athens│1 │┌──┬─────┬──────┐│
579−│ │ ││s#│sname│status││
580−│ │ │├──┼─────┼──────┤│
581−│ │ ││S5│Adams│30 ││
582−│ │ │└──┴─────┴──────┘│
583−└──────┴─────────┴─────────────────┘
586+└──────────┴──────────────────┴───────────────────────────────────────────────────────┘
584```
587```
585
588
586In 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.
589In 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.