Annotation of 43BSD/ingres/doc/other/tutorial.nr, revision 1.1.1.1

1.1       root        1: .de @h
                      2: 'sp 4
                      3: 'tl ''''
                      4: 'sp 2
                      5: .ns
                      6: ..
                      7: .wh 0 @h
                      8: .po 5
                      9: .rs
                     10: 
                     11: .sp 4
                     12: .ce
                     13: A TUTORIAL ON INGRES
                     14: .sp 15
                     15: .ce
                     16: by
                     17: .ce
                     18: Robert Epstein
                     19: .sp 18
                     20: .ce 3
                     21: Memorandum No. ERL - M77-25
                     22: December 15, 1977
                     23: (Revised)
                     24: .sp 3
                     25: .ce 4
                     26: Electronics Research Laboratory
                     27: College of Engineering
                     28: University of California, Berkeley
                     29: 94720
                     30: .bp 1
                     31: .de @f
                     32: 'sp 3
                     33: 'tl 'A Tutorial on INGRES''Page %'
                     34: 'bp
                     35: ..
                     36: .wh -7 @f
                     37: .rs
                     38: .ce 1
                     39: A Tutorial on INGRES
                     40: .sp 5
                     41: This tutorial describes how to use the INGRES data base
                     42: management system.
                     43: You should be able to follow the the examples
                     44: given here and observe the same results.
                     45: 
                     46: The data manipulation language supported by the
                     47: INGRES system is called
                     48: QUEL (QUEry Language).
                     49: Complete information on QUEL and INGRES appears
                     50: in the INGRES reference manual.
                     51: This tutorial does not attempt to
                     52: cover every detail of INGRES.
                     53: 
                     54: Begin by logging onto UNIX, the
                     55: time sharing system under which INGRES runs.
                     56: If at all possible, use a terminal
                     57: that has both upper and lower case letters;
                     58: otherwise life is going to be miserable for you.
                     59: If you are on an upper case only terminal,
                     60: type "\\\\" everywhere "\\" appears in the
                     61: tutorial.
                     62: 
                     63: There should currently be a "%" printed on your terminal.
                     64: To start using INGRES type the command:
                     65: .nf
                     66: 
                     67: % ingres demo
                     68: 
                     69: .fi
                     70: This requests "UNIX" to invoke INGRES using the
                     71: data base called "demo".
                     72: After a few seconds, the following will appear:
                     73: .nf
                     74: 
                     75: INGRES version 6.1/0 login
                     76: Tue Aug 30 14:52:23 1977
                     77: 
                     78: COPYRIGHT
                     79: The Regents of the University of California
                     80: 1977
                     81: 
                     82: This program material is the property of the
                     83: Regents of the University of California and
                     84: may not be reproduced or disclosed without
                     85: the prior written permission of the owner.
                     86: 
                     87: go
                     88: *
                     89: 
                     90: .fi
                     91: The first two lines include the INGRES version
                     92: number (in this case version 6.1) and the current date.
                     93: Following that is the "dayfile",
                     94: which includes
                     95: messages related to the
                     96: INGRES system.
                     97: The "go" indicates that INGRES
                     98: is ready for your interactions.
                     99: 
                    100: The INGRES monitor
                    101: prints an asterisk ("*") at the beginning of
                    102: each line
                    103: to remind you that INGRES is waiting for input.
                    104: 
                    105: Type the command:
                    106: .nf
                    107: 
                    108: * print parts
                    109: * \\g
                    110: Executing . . .
                    111: 
                    112: .fi
                    113: The line "print parts" requests a printout of
                    114: some data stored in the data base.
                    115: The "\\g" means "go".
                    116: The message "Executing . . ."
                    117: indicates that INGRES is processing your
                    118: query.
                    119: The following then appears:
                    120: .nf
                    121: 
                    122: parts relation
                    123: 
                    124: |pnum  |pname               |color   |weight|qoh   |
                    125: |--------------------------------------------------|
                    126: |     1|central processor   |pink    |    10|     1|
                    127: |     2|memory              |gray    |    20|    32|
                    128: |     3|disk drive          |black   |   685|     2|
                    129: |     4|tape drive          |black   |   450|     4|
                    130: |     5|tapes               |gray    |     1|   250|
                    131: |     6|line printer        |yellow  |   578|     3|
                    132: |     7|l-p paper           |white   |    15|    95|
                    133: |     8|terminals           |blue    |    19|    15|
                    134: |    13|paper tape reader   |black   |   107|     0|
                    135: |    14|paper tape punch    |black   |   147|     0|
                    136: |     9|terminal paper      |white   |     2|   350|
                    137: |    10|byte-soap           |clear   |     0|   143|
                    138: |    11|card reader         |gray    |   327|     0|
                    139: |    12|card punch          |gray    |   427|     0|
                    140: |--------------------------------------------------|
                    141: 
                    142: continue
                    143: *
                    144: 
                    145: .fi
                    146: What is printed on your terminal is the "parts relation".
                    147: Intuitively, a relation is nothing more that a
                    148: table with rows and columns.
                    149: 
                    150: In this case the relation name is "parts".
                    151: There are five columns (we call them domains)
                    152: named pnum (part number), pname (part name),
                    153: color, weight, qoh (quantity on hand).
                    154: Each row of the relation (called a tuple)
                    155: represents one entry, which in this
                    156: case represents one part in a computer
                    157: installation.
                    158: A relation can have up to 49 domains and a
                    159: virtually unlimited number of tuples.
                    160: 
                    161: Notice that after the query is executed, INGRES prints
                    162: "continue", while when we first entered INGRES
                    163: it printed "go".
                    164: As you enter a query INGRES
                    165: saves what you type in
                    166: a "workspace".
                    167: If you
                    168: ever mistype a query, typing "\\r"
                    169: will "reset" (ie. erase) your workspace.
                    170: (Later on we will
                    171: learn ways to edit mistakes so
                    172: we don't have to retype the entire query.)
                    173: 
                    174: At any time you can see what is in the
                    175: workspace by typing "\\p".
                    176: Try typing "\\p":
                    177: 
                    178: .nf
                    179: * \\p
                    180: print parts
                    181: *
                    182: 
                    183: .fi
                    184: The current contents of the workspace
                    185: is printed.
                    186: Now try typing "\\r":
                    187: 
                    188: .nf
                    189: * \\r
                    190: go
                    191: *
                    192: 
                    193: .fi
                    194: The workspace is now empty.
                    195: Whenever
                    196: INGRES types "continue" the
                    197: workspace is non-empty;
                    198: whenever INGRES types "go" the
                    199: workspace is empty.
                    200: 
                    201: After a query is executed,
                    202: INGRES typically types "continue".
                    203: If you then type a new query, INGRES
                    204: automatically erases the previous query,
                    205: so you don't have to type "\\r" after every query.
                    206: This will be further explained as we proceed.
                    207: 
                    208: Using the "retrieve" command we can write
                    209: specific queries about relations.
                    210: As an example, let's have INGRES
                    211: print only the "pname" domain of the parts
                    212: relation.
                    213: Type the command:
                    214: .nf
                    215: 
                    216: * range of p is parts
                    217: * retrieve (p.pname)
                    218: * \\g
                    219: Executing . . .
                    220: 
                    221: 
                    222: |pname               |
                    223: |--------------------|
                    224: |central processor   |
                    225: |memory              |
                    226: |disk drive          |
                    227: |tape drive          |
                    228: |tapes               |
                    229: |line printer        |
                    230: |l-p paper           |
                    231: |terminals           |
                    232: |paper tape reader   |
                    233: |paper tape punch    |
                    234: |terminal paper      |
                    235: |byte-soap           |
                    236: |card reader         |
                    237: |card punch          |
                    238: |--------------------|
                    239: 
                    240: continue
                    241: *
                    242: 
                    243: .fi
                    244: The output is just the pname domain from the
                    245: parts relation.
                    246: What we did required two steps.
                    247: First we declared what is called a "tuple variable"
                    248: and assigned it to range over the parts relation.
                    249: 
                    250: range of p is parts
                    251: 
                    252: What this means in English is that the letter "p"
                    253: represents the parts relation.
                    254: It may be thought of as a marker
                    255: which moves down the "parts" relation to
                    256: keep our place.
                    257: INGRES remembers the association so that
                    258: once p is declared to range over parts,
                    259: we don't have to repeat the range declaration.
                    260: This is useful when we are working
                    261: with more than one relation, as will be seen later on.
                    262: 
                    263: Next we used the retrieve command.
                    264: Its form is
                    265: 
                    266: retrieve ( list here what you want retrieved )
                    267: 
                    268: "p" by itself refers to the parts relation.
                    269: "p.pname" refers to the pname domain of the
                    270: parts relation, so saying:
                    271: 
                    272: retrieve (p.pname)
                    273: 
                    274: means retrieve the
                    275: pname domain of the parts relation.
                    276: 
                    277: Try the
                    278: query to retrieve pname and color:
                    279: 
                    280: .nf
                    281: * retrieve p.pname, p.color
                    282: * \\g
                    283: Executing . . .
                    284: 
                    285: 2500: syntax error on line 1
                    286: last symbol read was: .
                    287: 
                    288: continue
                    289: *
                    290: 
                    291: .fi
                    292: Unfortunately we've made an error.
                    293: INGRES tells us that it found a syntax
                    294: error on the first line of the query.
                    295: "Syntax error" means that we have
                    296: typed something which INGRES cannot recognize.
                    297: The error occured on line 1.
                    298: INGRES makes a sometimes helpful and
                    299: sometimes feeble attempt at
                    300: diagnosing the problem.
                    301: Whenever possible,
                    302: INGRES tells us the last thing it read before it got confused.
                    303: 
                    304: In this case, the error is that the list of things to be retrieved
                    305: (called the target list) must be enclosed in parenthesis.
                    306: The correct query is:
                    307: .nf
                    308: 
                    309: * retrieve (p.pname, p.color)
                    310: * \\g
                    311: Executing . . .
                    312: 
                    313: 
                    314: |pname               |color   |
                    315: |-----------------------------|
                    316: |central processor   |pink    |
                    317: |memory              |gray    |
                    318: |disk drive          |black   |
                    319: |tape drive          |black   |
                    320: |tapes               |gray    |
                    321: |line printer        |yellow  |
                    322: |l-p paper           |white   |
                    323: |terminals           |blue    |
                    324: |paper tape reader   |black   |
                    325: |paper tape punch    |black   |
                    326: |terminal paper      |white   |
                    327: |byte-soap           |clear   |
                    328: |card reader         |gray    |
                    329: |card punch          |gray    |
                    330: |-----------------------------|
                    331: 
                    332: continue
                    333: *
                    334: 
                    335: .fi
                    336: You can restrict which tuples are printed by adding
                    337: a "qualification" to the query.
                    338: For example to get the name and color of
                    339: only those parts which are gray, type:
                    340: .nf
                    341: 
                    342: * retrieve (p.pname, p.color)
                    343: * where p.color = "gray"
                    344: * \\g
                    345: Executing . . .
                    346: 
                    347: 
                    348: |pname               |color   |
                    349: |-----------------------------|
                    350: |memory              |gray    |
                    351: |tapes               |gray    |
                    352: |card reader         |gray    |
                    353: |card punch          |gray    |
                    354: |-----------------------------|
                    355: 
                    356: continue
                    357: *
                    358: 
                    359: .fi
                    360: Notice that INGRES prints only those parts where p.color
                    361: is gray.
                    362: Notice also that gray must be in quotes ("gray").
                    363: This is necessary.
                    364: The only way INGRES will recognize character strings
                    365: (e.g. words) is to enclose them in quotes.
                    366: 
                    367: What if we wanted part names for gray or pink parts?
                    368: We only need to append to the previous
                    369: query the phrase:
                    370: 
                    371: or p.color = "pink"
                    372: 
                    373: Remember, however, that if the next
                    374: line typed begins a new query, INGRES
                    375: will automatically reset the workspace.
                    376: The workspace will be
                    377: .ul 
                    378: saved
                    379: only if the next line begins with a command
                    380: such as "\\p" or "\\g".
                    381: (There are others which we will come to later.)  
                    382: If such a command is typed,
                    383: the previous query is saved and anything
                    384: further will be appended to that query.
                    385: 
                    386: Thus, by typing:
                    387: .nf
                    388: 
                    389: * \\p
                    390: retrieve (p.pname, p.color)
                    391: where p.color = "gray"
                    392: *
                    393: 
                    394: .fi
                    395: you can see the previous query.
                    396: Now type:
                    397: .nf
                    398: 
                    399: * or p.color = "pink"
                    400: *
                    401: 
                    402: .fi
                    403: INGRES appends that last line to
                    404: the end of the query.
                    405: You can verify this yourself by printing the workspace:
                    406: .nf
                    407: 
                    408: * \\p
                    409: retrieve (p.pname, p.color)
                    410: where p.color = "gray"
                    411: or p.color = "pink"
                    412: *
                    413: 
                    414: .fi
                    415: Now run the query:
                    416: .nf
                    417: 
                    418: * \\g
                    419: Executing . . .
                    420: 
                    421: 
                    422: |pname               |color   |
                    423: |-----------------------------|
                    424: |central processor   |pink    |
                    425: |memory              |gray    |
                    426: |tapes               |gray    |
                    427: |card reader         |gray    |
                    428: |card punch          |gray    |
                    429: |-----------------------------|
                    430: 
                    431: continue
                    432: *
                    433: 
                    434: .fi
                    435: The rules about when the workspace is reset may be
                    436: very confusing at first.
                    437: In general, INGRES will do exactly what
                    438: you want without you having to think about it.
                    439: 
                    440: We have seen qualifications which used "or" and "=".
                    441: In general one can use:
                    442: 
                    443: .nf
                    444:        and
                    445:        or
                    446:        not
                    447:        =       (equal)
                    448:        !=      (not equal)
                    449:        >       (greater than)
                    450:        >=      (greater than or equal)
                    451:        <       (less than)
                    452:        <=      (less than or equal)
                    453: .fi
                    454: 
                    455: Evaluation occurs in the
                    456: order the qualification was typed (ie. left to right).
                    457: Parenthesis can be used to group things
                    458: in any arbitrary order.
                    459: 
                    460: INGRES can do computations on the data
                    461: stored in a relation.
                    462: For example, the parts relation has
                    463: quantity on hand and weight for each item.
                    464: We might like to know the total weight
                    465: for each group of parts (i.e. weight multiplied by qoh).
                    466: 
                    467: To get the name, part number and total weight
                    468: for each part type the query:
                    469: .nf
                    470: 
                    471: * retrieve (p.pname, p.pnum, p.qoh * p.weight)
                    472: * \\g
                    473: Executing . . .
                    474: 
                    475: 2500: syntax error on line 1
                    476: last symbol read was: *
                    477: 
                    478: continue
                    479: *
                    480: 
                    481: .fi
                    482: Another error.
                    483: The problem is that when a computation
                    484: is done, INGRES does not know how to
                    485: title the domain on the printout.
                    486: For a simple domain, INGRES uses the
                    487: domain name as a title.
                    488: For anything else, you must
                    489: create a new domain title by specifying:
                    490: .nf
                    491: 
                    492:        tot = p.qoh * p.weight
                    493: 
                    494: .fi
                    495: More generally the form is:
                    496: .nf
                    497: 
                    498:        title = expression
                    499: 
                    500: .fi
                    501: For example:
                    502: .nf
                    503: 
                    504:        name = p.pname
                    505:        computation = p.weight / 2000 * (p.qoh + 2)
                    506: 
                    507: .fi
                    508: Let's fix the error by retyping
                    509: the query.
                    510: As long as the first line after a query
                    511: does not begin with a "\\p" or "\\g" then
                    512: INGRES will automatically reset
                    513: the workspace, erasing the previous
                    514: query for us.
                    515: .nf
                    516: 
                    517: * retrieve (p.pname, p.pnum, tot=p.qoh * p.weight)
                    518: * \\g
                    519: Executing . . .
                    520: 
                    521: 
                    522: |pname               |pnum  |tot   |
                    523: |----------------------------------|
                    524: |central processor   |     1|    10|
                    525: |memory              |     2|   640|
                    526: |disk drive          |     3|  1370|
                    527: |tape drive          |     4|  1800|
                    528: |tapes               |     5|   250|
                    529: |line printer        |     6|  1734|
                    530: |l-p paper           |     7|  1425|
                    531: |terminals           |     8|   285|
                    532: |paper tape reader   |    13|     0|
                    533: |paper tape punch    |    14|     0|
                    534: |terminal paper      |     9|   700|
                    535: |byte-soap           |    10|     0|
                    536: |card reader         |    11|     0|
                    537: |card punch          |    12|     0|
                    538: |----------------------------------|
                    539: 
                    540: continue
                    541: *
                    542: 
                    543: .fi
                    544: In addition to multiplication, INGRES supports:
                    545: .in +8
                    546: 
                    547: +   addition
                    548: .br
                    549: -   subtraction (and unary negation)
                    550: .br
                    551: /   division
                    552: .br
                    553: *   multiplication
                    554: .br
                    555: **  exponentiation (e.g. 3**10)
                    556: .br
                    557: abs  absolute value (e.g. abs(p.qoh - 50) )
                    558: .br
                    559: mod  modulo division
                    560: .br
                    561: 
                    562: .in -8
                    563: and many others.
                    564: Please refer to the INGRES reference manual for
                    565: a brief but complete description of
                    566: what is supported.
                    567: 
                    568: If all we wanted were part numbers 2 or 10,
                    569: then we could add the qualification:
                    570: 
                    571:        where p.pnum = 2 or p.pnum = 10
                    572: 
                    573: CAUTION: if we just started typing "where p.pnum .... "
                    574: INGRES would understand this as the
                    575: beginning of a new query
                    576: and would reset the workspace.
                    577: To avoid this you could type "\\p" and force INGRES
                    578: to print the workspace,
                    579: or you can type "\\a" (append).
                    580: The append command guarantees that whatever
                    581: else is typed will be appended to
                    582: what is already in the workspace.
                    583: This command is only needed immediately after
                    584: a query is executed.
                    585: Any other time data will be appended automatically.
                    586: Try the following:
                    587: .nf
                    588: 
                    589: * \\a
                    590: * where p.pnum = 2 or p.pnum = 10
                    591: * \\g
                    592: Executing . . .
                    593: 
                    594: 
                    595: |pname               |pnum  |tot   |
                    596: |----------------------------------|
                    597: |memory              |     2|   640|
                    598: |byte-soap           |    10|     0|
                    599: |----------------------------------|
                    600: 
                    601: continue
                    602: *
                    603: 
                    604: .fi
                    605: To include all part numbers greater than 2 and less than or
                    606: equal to 10:
                    607: .nf
                    608: 
                    609: * retrieve (p.pname, p.pnum, tot=p.qoh * p.weight)
                    610: * where p.pnum > 2 and p.pnum <= 10
                    611: * \\g
                    612: Executing . . .
                    613: 
                    614: 
                    615: |pname               |pnum  |tot   |
                    616: |----------------------------------|
                    617: |disk drive          |     3|  1370|
                    618: |tape drive          |     4|  1800|
                    619: |tapes               |     5|   250|
                    620: |line printer        |     6|  1734|
                    621: |l-p paper           |     7|  1425|
                    622: |terminals           |     8|   285|
                    623: |terminal paper      |     9|   700|
                    624: |byte-soap           |    10|     0|
                    625: |----------------------------------|
                    626: 
                    627: continue
                    628: *
                    629: 
                    630: .fi
                    631: Now, suppose we want to change
                    632: the previous query to give results
                    633: for part numbers between 5 and 10
                    634: instead of 2 and 10.
                    635: You are probably annoyed at having to retype
                    636: the entire query in order to
                    637: change one character.
                    638: Consequently,
                    639: INGRES lets you use the UNIX text editor
                    640: to make corrections and/or additions
                    641: to your workspace.
                    642: At any time you can type "\\e" and the
                    643: INGRES monitor will write your workspace to a file
                    644: and call the UNIX "ed" program.
                    645: For example:
                    646: .nf
                    647: 
                    648: * \\e
                    649: >>ed
                    650: 83
                    651: 
                    652: .fi
                    653: The ">>ed" message tells you that you are now using the
                    654: editor.
                    655: The number 83 is the number of characters in your workspace.
                    656: 
                    657: We can now edit the query by changing the
                    658: 2 to a 5.
                    659: Included in the UNIX documentation is a tutorial on using the
                    660: text editor.
                    661: Rather than duplicating that tutorial, we will just
                    662: use a few of the editor commands to illustrate how
                    663: to do editing:
                    664: .nf
                    665: 
                    666: 1p
                    667: retrieve (p.pname,p.pnum,tot = p.qoh * p.weight)
                    668: 2p
                    669: where p.pnum > 2 and p.pnum <= 10
                    670: s/2/5/p
                    671: where p.pnum > 5 and p.pnum <= 10
                    672: w
                    673: 83
                    674: q
                    675: <<monitor
                    676: *
                    677: 
                    678: .fi
                    679: Very briefly, this is what happens.
                    680: "1p" and "2p" printed lines 1 and 2.
                    681: "s/2/5/p" substitutes a 5 for a 2 on the current
                    682: line (line 2), and then prints that line.
                    683: "w" writes the query back to the INGRES workspace.
                    684: 
                    685: Inside the editor you can use any "ed" command
                    686: except "e" (since e changes the file name).
                    687: When you quit the editor (q command),
                    688: the INGRES monitor will print "<<monitor" to
                    689: remind you that you are back in INGRES.
                    690: Notice that you MUST precede the "q" command with
                    691: a "w" command
                    692: to pass the
                    693: corrected workspace back to INGRES.
                    694: 
                    695: To verify that the query is correct and to run it, type:
                    696: .nf
                    697: * \\p\\g
                    698: retrieve (p.pname,p.pnum,tot = p.qoh * p.weight)
                    699: where p.pnum > 5 and p.pnum <= 10
                    700: Executing . . .
                    701: 
                    702: 
                    703: |pname               |pnum  |tot   |
                    704: |----------------------------------|
                    705: |line printer        |     6|  1734|
                    706: |l-p paper           |     7|  1425|
                    707: |terminals           |     8|   285|
                    708: |terminal paper      |     9|   700|
                    709: |byte-soap           |    10|     0|
                    710: |----------------------------------|
                    711: 
                    712: continue
                    713: *
                    714: 
                    715: .fi
                    716: 
                    717: Having exhausted the
                    718: interesting queries concerning the parts relation, lets now
                    719: look at a new relation called "supply".
                    720: Type:
                    721: .nf
                    722: 
                    723: * print supply
                    724: * \\g
                    725: Executing . . .
                    726: 
                    727: 
                    728: supply relation
                    729: 
                    730: |snum  |pnum  |jnum  |shipdate|quan  |
                    731: |------------------------------------|
                    732: |   475|     1|  1001|73-12-31|     1|
                    733: |   475|     2|  1002|74-05-31|    32|
                    734: |   475|     3|  1001|73-12-31|     2|
                    735: |   475|     4|  1002|74-05-31|     1|
                    736: |   122|     7|  1003|75-02-01|   144|
                    737: |   122|     7|  1004|75-02-01|    48|
                    738: |   122|     9|  1004|75-02-01|   144|
                    739: |   440|     6|  1001|74-10-10|     2|
                    740: |   241|     4|  1001|73-12-31|     1|
                    741: |    62|     3|  1002|74-06-18|     3|
                    742: |   475|     2|  1001|73-12-31|    32|
                    743: |   475|     1|  1002|74-07-01|     1|
                    744: |     5|     4|  1003|74-11-15|     3|
                    745: |     5|     4|  1004|75-01-22|     6|
                    746: |    20|     5|  1001|75-01-10|    20|
                    747: |    20|     5|  1002|75-01-10|    75|
                    748: |   241|     1|  1005|75-06-01|     1|
                    749: |   241|     2|  1005|75-06-01|    32|
                    750: |   241|     3|  1005|75-06-01|     1|
                    751: |    67|     4|  1005|75-07-01|     1|
                    752: |   999|    10|  1006|76-01-01|   144|
                    753: |   241|     8|  1005|75-07-01|     1|
                    754: |   241|     9|  1005|75-07-01|   144|
                    755: |------------------------------------|
                    756: 
                    757: continue
                    758: *
                    759: 
                    760: .fi
                    761: The supply relation contains snum (the supplier number),
                    762: pnum (the part number which is supplied by that supplier),
                    763: jnum (the job number),
                    764: shipdate (the date it was shipped),
                    765: and quan (the quantity shipped).
                    766: 
                    767: To find out what parts are supplied by supplier number 122 type:
                    768: .nf
                    769: 
                    770: * retrieve (s.pnum) where s.snum = 122
                    771: * \\g
                    772: Executing . . .
                    773: 
                    774: 2109: line 1, Variable 's' not declared in RANGE statement
                    775: 
                    776: continue
                    777: *
                    778: 
                    779: .fi
                    780: We have referenced the tuple variable "s"
                    781: (i.e. s.pnum) without telling INGRES what
                    782: "s" represents.
                    783: We are missing a range declaration.
                    784: Retype the query as follows:
                    785: .nf
                    786: 
                    787: * range of s is supply
                    788: * retrieve (s.pnum) where s.snum = 122
                    789: * \\g
                    790: Executing . . .
                    791: 
                    792: 
                    793: |pnum  |
                    794: |------|
                    795: |     7|
                    796: |     7|
                    797: |     9|
                    798: |------|
                    799: 
                    800: continue
                    801: *
                    802: 
                    803: .fi
                    804: Supplier number 122 supplies part numbers 7, 7 and 9.
                    805: Note that 7 is listed twice.
                    806: When retrieving tuples onto a terminal it is
                    807: more efficient for INGRES NOT to check for duplicate
                    808: tuples.
                    809: INGRES can be forced to remove duplicate tuples.
                    810: We will come to that later.
                    811: 
                    812: We now know that supplier 122 supplies
                    813: part numbers 7 and 9.
                    814: If you haven't run this query a few hundred
                    815: times you probably don't know what part
                    816: names correspond to part numbers 7 and 9.
                    817: We could find out simply by
                    818: running the query:
                    819: .nf
                    820: 
                    821: * retrieve (p.pname) where p.pnum = 7 or
                    822: * p.pnum = 9
                    823: * \\g
                    824: Executing . . .
                    825: 
                    826: 
                    827: |pname               |
                    828: |--------------------|
                    829: |l-p paper           |
                    830: |terminal paper      |
                    831: |--------------------|
                    832: 
                    833: continue
                    834: *
                    835: 
                    836: .fi
                    837: After two queries we know by part name
                    838: what parts are supplied by supplier number 122.
                    839: We could do the same thing in one query by asking:
                    840: .nf
                    841: 
                    842: * retrieve (p.pname) where p.pnum = s.pnum
                    843: * and s.snum = 122
                    844: * \\g
                    845: Executing . . .
                    846: 
                    847: 
                    848: |pname               |
                    849: |--------------------|
                    850: |l-p paper           |
                    851: |l-p paper           |
                    852: |terminal paper      |
                    853: |--------------------|
                    854: 
                    855: continue
                    856: *
                    857: 
                    858: .fi
                    859: Again note that "l-p paper" is duplicated.
                    860: Look closely at this query.
                    861: Note that the domain pnum exists in both
                    862: the parts and supply relations.
                    863: By saying p.pnum = s.pnum, we are logically
                    864: joining the two relations.
                    865: 
                    866: Suppose we wished to find all suppliers who supply
                    867: the central processor.
                    868: We know that we will want to retrieve s.snum.
                    869: We want only those s.snum's where the corresponding s.pnum
                    870: is equal to the part number for the central
                    871: processor.
                    872: 
                    873: If we find the p.pname which is equal to "central processor"
                    874: then that will tell us the correct p.pnum.
                    875: Finally we want s.pnum = p.pnum.
                    876: The query is:
                    877: .nf
                    878: 
                    879: * retrieve (s.snum) where
                    880: * s.pnum = p.pnum and p.pname = "central processor"
                    881: * \\g
                    882: Executing . . .
                    883: 
                    884: 
                    885: |snum  |
                    886: |------|
                    887: |   475|
                    888: |   475|
                    889: |   241|
                    890: |------|
                    891: 
                    892: continue
                    893: *
                    894: 
                    895: .fi
                    896: Let's abandon the parts and supply relations and try another.
                    897: First, we can see what other relations are in the
                    898: database by typing:
                    899: .nf
                    900: 
                    901: * help \\g
                    902: * Executing . . .
                    903: 
                    904: 
                    905:  relation name     relation owner
                    906: 
                    907:  relation          ingres
                    908:  attribute         ingres
                    909:  indexes           ingres
                    910:  integrity         ingres
                    911:  constraint        ingres
                    912:  item              ingres
                    913:  sale              ingres
                    914:  employee          ingres
                    915:  dept              ingres
                    916:  supplier          ingres
                    917:  store             ingres
                    918:  parts             ingres
                    919:  supply            ingres
                    920: 
                    921: 
                    922: continue
                    923: * 
                    924: 
                    925: .fi
                    926: Let's look at the "employee" relation.
                    927: Since we know nothing about the relation we
                    928: can also use the "help" command to learn about it.
                    929: Type:
                    930: .nf
                    931: 
                    932: * help employee
                    933: * \\g
                    934: Executing . . .
                    935: 
                    936: 
                    937: Relation:              employee
                    938: Owner:                 ingres
                    939: Tuple width:           30
                    940: Saved until:           Fri Mar 25 11:01:30 1977
                    941: Number of tuples:      24
                    942: Storage structure:     paged heap
                    943: relation type:         user relation
                    944: 
                    945:  attribute name    type  length  keyno.
                    946: 
                    947:  number            i       2
                    948:  name              c      20
                    949:  salary            i       2
                    950:  manager           i       2
                    951:  birthdate         i       2
                    952:  startdate         i       2
                    953: 
                    954: 
                    955: continue
                    956: * 
                    957: 
                    958: .fi
                    959: The help command lists overall information
                    960: about the employee relation
                    961: together with each attribute, its
                    962: type and its length.
                    963: 
                    964: INGRES supports three data types: integer numbers,
                    965: floating point numbers, and characters strings.
                    966: Character domains can be from 1 to 255 characters
                    967: in length.
                    968: Integer domains can be 1, 2, or 4 bytes in length.
                    969: This means that integers can obtain a maximum
                    970: value of 127; 32,767; and 2,147,483,647 respectively.
                    971: Floating point numbers can be either 4 or 8 bytes.
                    972: Both hold a maximum value of about 10**38;
                    973: with 7 or 17 digit accuracy respectively.
                    974: 
                    975: To look at all domains we could use the print command
                    976: or we could use the retrieve command and
                    977: list each domain in the target list.
                    978: INGRES provides a shorthand way of doing just that.
                    979: Try the following:
                    980: .nf
                    981: 
                    982: * range of e is employee
                    983: * retrieve (e.all)
                    984: * \\g
                    985: Executing . . .
                    986: 
                    987: 
                    988: |number|name                |salary|manage|birthd|startd|
                    989: |-------------------------------------------------------|
                    990: |   157|Jones, Tim          | 12000|   199|  1940|  1960|
                    991: |  1110|Smith, Paul         |  6000|    33|  1952|  1973|
                    992: |    35|Evans, Michael      |  5000|    32|  1952|  1974|
                    993: |   129|Thomas, Tom         | 10000|   199|  1941|  1962|
                    994: |    13|Edwards, Peter      |  9000|   199|  1928|  1958|
                    995: |   215|Collins, Joanne     |  7000|    10|  1950|  1971|
                    996: |    55|James, Mary         | 12000|   199|  1920|  1969|
                    997: |    26|Thompson, Bob       | 13000|   199|  1930|  1970|
                    998: |    98|Williams, Judy      |  9000|   199|  1935|  1969|
                    999: |    32|Smythe, Carol       |  9050|   199|  1929|  1967|
                   1000: |    33|Hayes, Evelyn       | 10100|   199|  1931|  1963|
                   1001: |   199|Bullock, J.D.       | 27000|     0|  1920|  1920|
                   1002: |  4901|Bailey, Chas M.     |  8377|    32|  1956|  1975|
                   1003: |   843|Schmidt, Herman     | 11204|    26|  1936|  1956|
                   1004: |  2398|Wallace, Maggie J.  |  7880|    26|  1940|  1959|
                   1005: |  1639|Choy, Wanda         | 11160|    55|  1947|  1970|
                   1006: |  5119|Ferro, Tony         | 13621|    55|  1939|  1963|
                   1007: |    37|Raveen, Lemont      | 11985|    26|  1950|  1974|
                   1008: |  5219|Williams, Bruce     | 13374|    33|  1944|  1959|
                   1009: |  1523|Zugnoni, Arthur A.  | 19868|   129|  1928|  1949|
                   1010: |   430|Brunet, Paul C.     | 17674|   129|  1938|  1959|
                   1011: |   994|Iwano, Masahiro     | 15641|   129|  1944|  1970|
                   1012: |  1330|Onstad, Richard     |  8779|    13|  1952|  1971|
                   1013: |    10|Ross, Stanley       | 15908|   199|  1927|  1945|
                   1014: |    11|Ross, Stuart        | 12067|     0|  1931|  1932|
                   1015: |-------------------------------------------------------|
                   1016: 
                   1017: continue
                   1018: *
                   1019: 
                   1020: .fi
                   1021: "All" is a keyword which is expanded by
                   1022: INGRES to become all domains.
                   1023: The domains are not guaranteed to be in any particular order.
                   1024: The previous query is equivalent to:
                   1025: .nf
                   1026: 
                   1027:        range of e is employee
                   1028:        retrieve (e.number, e.name, e.salary, e.manager
                   1029:                e.birthdate, e.startdate)
                   1030: 
                   1031: .fi
                   1032: Let's retrieve the salary of Stan Ross.
                   1033: At this point we will need to be able
                   1034: to type both upper and lower case letters.
                   1035: If you are on an upper case only terminal,
                   1036: type a single "\\" before a letter
                   1037: you wish to capitalize.
                   1038: Thus on an upper case only terminal
                   1039: type "\\ROSS, \\STAN".
                   1040: If you are on an upper and lower case
                   1041: terminal, use the shift key to
                   1042: capitalize a letter.
                   1043: 
                   1044: Run the query:
                   1045: .nf
                   1046: 
                   1047: * retrieve (e.name,e.salary)
                   1048: * where e.name = "Ross, Stan"
                   1049: * \\g
                   1050: Executing . . .
                   1051: 
                   1052: 
                   1053: |name                |salary|
                   1054: |---------------------------|
                   1055: |---------------------------|
                   1056: 
                   1057: continue
                   1058: *
                   1059: 
                   1060: .fi
                   1061: The result is empty.
                   1062: There is no e.name which satisfies the qualification.
                   1063: That's strange because we know there is a Stan Ross.
                   1064: However, INGRES does not know, for example, that "Stanley"
                   1065: and "Stan" are semantically the same.
                   1066: 
                   1067: To get the correct answer in this
                   1068: situation you may use the special
                   1069: "pattern matching" characters
                   1070: provided by INGRES.
                   1071: 
                   1072: One such character is "*".
                   1073: It matches any string of zero or more characters.
                   1074: Try the query:
                   1075: .nf
                   1076: 
                   1077: * retrieve (e.name,e.salary)
                   1078: * where e.name = "Ross, S*"
                   1079: * \\g
                   1080: Executing . . .
                   1081: 
                   1082: 
                   1083: |name                |salary|
                   1084: |---------------------------|
                   1085: |Ross, Stanley       | 15908|
                   1086: |Ross, Stuart        | 12067|
                   1087: |---------------------------|
                   1088: 
                   1089: continue
                   1090: *
                   1091: 
                   1092: .fi
                   1093: In the first case "*" matched the string "tanley" and
                   1094: in the second case it matched "tuart".
                   1095: 
                   1096: Here is another example.
                   1097: Find the salaries of all people
                   1098: whose first name is "Paul":
                   1099: .nf
                   1100: 
                   1101: * retrieve (e.name,e.salary)
                   1102: * where e.name = "*,Paul*"
                   1103: * \\g
                   1104: Executing . . .
                   1105: 
                   1106: 
                   1107: |name                |salary|
                   1108: |---------------------------|
                   1109: |Smith, Paul         |  6000|
                   1110: |Brunet, Paul C.     | 17674|
                   1111: |---------------------------|
                   1112: 
                   1113: continue
                   1114: *
                   1115: 
                   1116: .fi
                   1117: Notice that if we had asked for e.name = "*,Paul"
                   1118: we would not have gotten the second tuple.
                   1119: Also,
                   1120: INGRES ignores blanks
                   1121: in any character
                   1122: comparison whether using pattern matching
                   1123: characters or not.
                   1124: This means that the following would all give the same results:
                   1125: .nf
                   1126: 
                   1127:        e.name = "Ross,Stanley"
                   1128:        e.name = "Ross,   Stanley   "
                   1129:        e.name = "R o s s,Stanley"
                   1130: 
                   1131: .fi
                   1132: Particular characters or ranges of characters can be put
                   1133: in square brackets ([]).
                   1134: For example, find all people whose names start with
                   1135: "B" through "F":
                   1136: .nf
                   1137: 
                   1138: * retrieve (e.name,e.salary)
                   1139: * where e.name = "[B-F]*"
                   1140: * \\g
                   1141: Executing . . .
                   1142: 
                   1143: 
                   1144: |name                |salary|
                   1145: |---------------------------|
                   1146: |Evans, Michael      |  5000|
                   1147: |Edwards, Peter      |  9000|
                   1148: |Collins, Joanne     |  7000|
                   1149: |Bullock, J.D.       | 27000|
                   1150: |Bailey, Chas M.     |  8377|
                   1151: |Choy, Wanda         | 11160|
                   1152: |Ferro, Tony         | 13621|
                   1153: |Brunet, Paul C.     | 17674|
                   1154: |---------------------------|
                   1155: 
                   1156: continue
                   1157: *
                   1158: 
                   1159: .fi
                   1160: Notice that this last query could be done another way:
                   1161: .nf
                   1162: 
                   1163: * retrieve (e.name,e.salary)
                   1164: * where e.name >"B" and e.name <"G"
                   1165: * \\g
                   1166: Executing . . .
                   1167: 
                   1168: 
                   1169: |name                |salary|
                   1170: |---------------------------|
                   1171: |Evans, Michael      |  5000|
                   1172: |Edwards, Peter      |  9000|
                   1173: |Collins, Joanne     |  7000|
                   1174: |Bullock, J.D.       | 27000|
                   1175: |Bailey, Chas M.     |  8377|
                   1176: |Choy, Wanda         | 11160|
                   1177: |Ferro, Tony         | 13621|
                   1178: |Brunet, Paul C.     | 17674|
                   1179: |---------------------------|
                   1180: 
                   1181: continue
                   1182: *
                   1183: 
                   1184: .fi
                   1185: The two results are identical;
                   1186: however, the second way is generally
                   1187: more efficient for INGRES to process.
                   1188: 
                   1189: There are three types of pattern matching constructs.
                   1190: All three can be used in any combination for
                   1191: character comparison.
                   1192: They are:
                   1193: 
                   1194: .in +8
                   1195: .ti -4
                   1196: *   matches any length character string
                   1197: .ti -4
                   1198: ?   matches any one (non-blank) character
                   1199: .ti -4
                   1200: [ ] can match any character listed in the brackets.
                   1201: If two characters are separated by a dash (-),
                   1202: then it matches any character falling
                   1203: between the two characters.
                   1204: .in -8
                   1205: 
                   1206: The special meaning of a pattern matching
                   1207: character can be turned off by preceeding
                   1208: it with a "\\".
                   1209: This means that "\\*" refers to the character
                   1210: "*".
                   1211: 
                   1212: We turn now to the aggregation
                   1213: facilities supported by INGRES.
                   1214: This allows a user to perform computations
                   1215: on whole domains of a relation.
                   1216: For example, one aggregate is average (avg).
                   1217: To compute the average salary for all employees, we enter:
                   1218: .nf
                   1219: 
                   1220: * retrieve (avgsal=avg(e.salary))
                   1221: * \\g
                   1222: Executing . . .
                   1223: 
                   1224: 
                   1225: |avgsal    |
                   1226: |----------|
                   1227: | 11867.520|
                   1228: |----------|
                   1229: 
                   1230: continue
                   1231: *
                   1232: 
                   1233: .fi
                   1234: The particular title "avgsal"
                   1235: is arbitrary, but necessary;
                   1236: INGRES needs
                   1237: .ul
                   1238: some
                   1239: sort of title for any
                   1240: expression in the target list
                   1241: (other than a simple domain).
                   1242: 
                   1243: We can also find the minimum and maximum salaries:
                   1244: .nf
                   1245: 
                   1246: * retrieve (minsal=min(e.salary),maxsal=max(e.salary))
                   1247: * \\g
                   1248: Executing . . .
                   1249: 
                   1250: 
                   1251: |minsal|maxsal|
                   1252: |-------------|
                   1253: |  5000| 27000|
                   1254: |-------------|
                   1255: 
                   1256: continue
                   1257: *
                   1258: 
                   1259: .fi
                   1260: If we wanted to know the names of the employees who
                   1261: make the minimum and maximum salaries, that query would be:
                   1262: .nf
                   1263: 
                   1264: * retrieve (e.name, e.salary)
                   1265: * where e.salary = min(e.salary) or e.salary = max(e.salary)
                   1266: * \\g
                   1267: Executing . . .
                   1268: 
                   1269: |name                |salary|
                   1270: |---------------------------|
                   1271: |Evans, Michael      |  5000|
                   1272: |Bullock, J.D.       | 27000|
                   1273: |---------------------------|
                   1274: 
                   1275: continue
                   1276: * 
                   1277: 
                   1278: .fi
                   1279: INGRES supports the following aggregates:
                   1280: .nf
                   1281: 
                   1282:        count
                   1283:        min
                   1284:        max
                   1285:        avg
                   1286:        sum
                   1287:        any
                   1288: 
                   1289: .fi
                   1290: We now indicate the query to list each employee along
                   1291: with the average salary for all employees:
                   1292: .nf
                   1293: 
                   1294: * retrieve (e.name,peersal=avg(e.salary))
                   1295: * \\g
                   1296: Executing . . .
                   1297: 
                   1298: 
                   1299: |name                |peersal   |
                   1300: |-------------------------------|
                   1301: |Jones, Tim          | 11867.520|
                   1302: |Smith, Paul         | 11867.520|
                   1303: |Evans, Michael      | 11867.520|
                   1304: |Thomas, Tom         | 11867.520|
                   1305: |Edwards, Peter      | 11867.520|
                   1306: |Collins, Joanne     | 11867.520|
                   1307: |James, Mary         | 11867.520|
                   1308: |Thompson, Bob       | 11867.520|
                   1309: |Williams, Judy      | 11867.520|
                   1310: |Smythe, Carol       | 11867.520|
                   1311: |Hayes, Evelyn       | 11867.520|
                   1312: |Bullock, J.D.       | 11867.520|
                   1313: |Bailey, Chas M.     | 11867.520|
                   1314: |Schmidt, Herman     | 11867.520|
                   1315: |Wallace, Maggie J.  | 11867.520|
                   1316: |Choy, Wanda         | 11867.520|
                   1317: |Ferro, Tony         | 11867.520|
                   1318: |Raveen, Lemont      | 11867.520|
                   1319: |Williams, Bruce     | 11867.520|
                   1320: |Zugnoni, Arthur A.  | 11867.520|
                   1321: |Brunet, Paul C.     | 11867.520|
                   1322: |Iwano, Masahiro     | 11867.520|
                   1323: |Onstad, Richard     | 11867.520|
                   1324: |Ross, Stanley       | 11867.520|
                   1325: |Ross, Stuart        | 11867.520|
                   1326: |-------------------------------|
                   1327: 
                   1328: continue
                   1329: *
                   1330: 
                   1331: .fi
                   1332: An aggregate always evaluates to a single value.
                   1333: To process the last query,
                   1334: INGRES replicated the average salary next to
                   1335: each e.name.
                   1336: 
                   1337: Aggregates can have their own qualification.
                   1338: For example, we can retrieve a list of each
                   1339: employee along with the average salary
                   1340: of those employees over 50.
                   1341: .nf
                   1342: 
                   1343: * retrieve (e.name,peersal=
                   1344: * avg(e.salary where 1977-e.birthdate > 50))
                   1345: * \\g
                   1346: Executing . . .
                   1347: 
                   1348: 
                   1349: |name                |peersal   |
                   1350: |-------------------------------|
                   1351: |Jones, Tim          | 19500.000|
                   1352: |Smith, Paul         | 19500.000|
                   1353: |Evans, Michael      | 19500.000|
                   1354: |Thomas, Tom         | 19500.000|
                   1355: |Edwards, Peter      | 19500.000|
                   1356: |Collins, Joanne     | 19500.000|
                   1357: |James, Mary         | 19500.000|
                   1358: |Thompson, Bob       | 19500.000|
                   1359: |Williams, Judy      | 19500.000|
                   1360: |Smythe, Carol       | 19500.000|
                   1361: |Hayes, Evelyn       | 19500.000|
                   1362: |Bullock, J.D.       | 19500.000|
                   1363: |Bailey, Chas M.     | 19500.000|
                   1364: |Schmidt, Herman     | 19500.000|
                   1365: |Wallace, Maggie J.  | 19500.000|
                   1366: |Choy, Wanda         | 19500.000|
                   1367: |Ferro, Tony         | 19500.000|
                   1368: |Raveen, Lemont      | 19500.000|
                   1369: |Williams, Bruce     | 19500.000|
                   1370: |Zugnoni, Arthur A.  | 19500.000|
                   1371: |Brunet, Paul C.     | 19500.000|
                   1372: |Iwano, Masahiro     | 19500.000|
                   1373: |Onstad, Richard     | 19500.000|
                   1374: |Ross, Stanley       | 19500.000|
                   1375: |Ross, Stuart        | 19500.000|
                   1376: |-------------------------------|
                   1377: 
                   1378: continue
                   1379: *
                   1380: 
                   1381: .fi
                   1382: Contrast the previous query with this next one.
                   1383: We will retrieve the names of those employees over fifty and
                   1384: retrieve the average salary for all employees.
                   1385: .nf
                   1386: 
                   1387: * retrieve (e.name,peersal=avg(e.salary))
                   1388: * where 1977-e.birthdate > 50
                   1389: * \\g
                   1390: Executing . . .
                   1391: 
                   1392: 
                   1393: |name                |peersal   |
                   1394: |-------------------------------|
                   1395: |James, Mary         | 11867.520|
                   1396: |Bullock, J.D.       | 11867.520|
                   1397: |-------------------------------|
                   1398: 
                   1399: continue
                   1400: *
                   1401: 
                   1402: .fi
                   1403: There is a very important distinction between these
                   1404: last two queries.
                   1405: An aggregate is completely self-contained.
                   1406: It is not affected by the qualification of the
                   1407: query as a whole.
                   1408: 
                   1409: In the first case, average is computed only for
                   1410: those employees over fifty, and all employees are retrieved.
                   1411: In the second case, however, average is computed for all
                   1412: employees but only those employees over 50 are retrieved.
                   1413: 
                   1414: If we wanted a list of all employees over fifty together
                   1415: with the average salary of employees over fifty,
                   1416: we would combine the previous two queries into one.
                   1417: That query would be:
                   1418: 
                   1419: .nf
                   1420: * retrieve (e.name, peersal=
                   1421: * avg(e.salary where 1977 - e.birthdate > 50))
                   1422: * where 1977 - e.birthdate > 50
                   1423: * \\g
                   1424: Executing . . .
                   1425: 
                   1426: 
                   1427: |name                |peersal   |
                   1428: |-------------------------------|
                   1429: |James, Mary         | 19500.000|
                   1430: |Bullock, J.D.       | 19500.000|
                   1431: |-------------------------------|
                   1432: 
                   1433: continue
                   1434: * 
                   1435: 
                   1436: .fi
                   1437: It is sometimes useful to have duplicate values removed before
                   1438: an aggregation is computed.
                   1439: For example if you wanted to know how many managers there are,
                   1440: the following query will not give the right answer:
                   1441: 
                   1442: .nf
                   1443: * retrieve (bosses = count(e.manager))
                   1444: * \\g
                   1445: * Executing . . .
                   1446: 
                   1447: 
                   1448: |bosses       |
                   1449: |-------------|
                   1450: |           25|
                   1451: |-------------|
                   1452: 
                   1453: continue
                   1454: * 
                   1455: 
                   1456: .fi
                   1457: Notice that that gives the count of how many tuples there are in
                   1458: employee.
                   1459: What we want to know is
                   1460: how many unique e.manager's there are.
                   1461: 
                   1462: INGRES provides three special forms of
                   1463: aggregation.
                   1464: 
                   1465: .nf
                   1466:        countu          count unique values
                   1467:        avgu            average unique values
                   1468:        sumu            sum unique values
                   1469: .fi
                   1470: 
                   1471: It's interesting to note that minu, maxu, and anyu are
                   1472: not needed.
                   1473: Their values would be the same whether duplicates were
                   1474: removed or not.
                   1475: 
                   1476: The correct query to find the number of managers is:
                   1477: 
                   1478: .nf
                   1479: * retrieve (bosses=countu(e.manager))
                   1480: * \\g
                   1481: Executing . . .
                   1482: 
                   1483: 
                   1484: |bosses       |
                   1485: |-------------|
                   1486: |            9|
                   1487: |-------------|
                   1488: 
                   1489: continue
                   1490: *
                   1491: 
                   1492: .fi
                   1493: Another aggregate facility supported by INGRES is called aggregate functions.
                   1494: Aggregate functions group
                   1495: data into categories and perform separate aggregations on each category.
                   1496: 
                   1497: For example,
                   1498: what if you wanted to retrieve each employee,
                   1499: and the average salary paid to employees with the same manager?
                   1500: That query would be:
                   1501: .nf
                   1502: 
                   1503: * retrieve (e.name,manageravg=avg(e.salary by e.manager))
                   1504: * \\g
                   1505: Executing . . .
                   1506: 
                   1507: 
                   1508: |name                |manageravg|
                   1509: |-------------------------------|
                   1510: |Jones, Tim          | 11117.555|
                   1511: |Thomas, Tom         | 11117.555|
                   1512: |Edwards, Peter      | 11117.555|
                   1513: |James, Mary         | 11117.555|
                   1514: |Thompson, Bob       | 11117.555|
                   1515: |Williams, Judy      | 11117.555|
                   1516: |Smythe, Carol       | 11117.555|
                   1517: |Hayes, Evelyn       | 11117.555|
                   1518: |Ross, Stanley       | 11117.555|
                   1519: |Smith, Paul         |  9687.000|
                   1520: |Williams, Bruce     |  9687.000|
                   1521: |Evans, Michael      |  6688.500|
                   1522: |Bailey, Chas M.     |  6688.500|
                   1523: |Collins, Joanne     |  7000.000|
                   1524: |Bullock, J.D.       | 19533.500|
                   1525: |Ross, Stuart        | 19533.500|
                   1526: |Schmidt, Herman     | 10356.333|
                   1527: |Wallace, Maggie J.  | 10356.333|
                   1528: |Raveen, Lemont      | 10356.333|
                   1529: |Choy, Wanda         | 12390.500|
                   1530: |Ferro, Tony         | 12390.500|
                   1531: |Zugnoni, Arthur A.  | 17727.666|
                   1532: |Brunet, Paul C.     | 17727.666|
                   1533: |Iwano, Masahiro     | 17727.666|
                   1534: |Onstad, Richard     |  8779.000|
                   1535: |-------------------------------|
                   1536: 
                   1537: continue
                   1538: *
                   1539: 
                   1540: .fi
                   1541: The first nine people all have the same manager and their
                   1542: average salary is 11117.555.
                   1543: The next two people have the same manager and their average
                   1544: salary is 9687. etc.
                   1545: 
                   1546: Once again, if we wanted to see the same list
                   1547: just for those employees over 50:
                   1548: .nf
                   1549: 
                   1550: * retrieve (e.name,manageravg=avg(e.salary by e.manager))
                   1551: * where 1977-e.birthdate > 50
                   1552: * \\g
                   1553: Executing . . .
                   1554: 
                   1555: 
                   1556: |name                |manageravg|
                   1557: |-------------------------------|
                   1558: |James, Mary         | 11117.555|
                   1559: |Bullock, J.D.       | 19533.500|
                   1560: |-------------------------------|
                   1561: 
                   1562: continue
                   1563: *
                   1564: 
                   1565: .fi
                   1566: Aggregate functions (unlike simple aggregates)
                   1567: are not completely local to themselves.
                   1568: The domains upon which the data is grouped
                   1569: (called the by-list) are logically
                   1570: connected to the domains in the rest of the query.
                   1571: 
                   1572: In these last examples, the "e.manager" in
                   1573: the by-list refers to the same tuple as
                   1574: "e.name" in the target list.
                   1575: 
                   1576: If we wanted to compute the average salaries by
                   1577: manager for only managers 33 and 199,
                   1578: then the query would be:
                   1579: .nf
                   1580: 
                   1581: * retrieve (e.name,manageravg=
                   1582: * avg(e.salary by e.manager)
                   1583: * where e.manager = 199 or e.manager = 33
                   1584: * \\g
                   1585: Executing . . .
                   1586: 
                   1587: 
                   1588: |name                |manageravg|
                   1589: |-------------------------------|
                   1590: |Jones, Tim          | 11117.555|
                   1591: |Thomas, Tom         | 11117.555|
                   1592: |Edwards, Peter      | 11117.555|
                   1593: |James, Mary         | 11117.555|
                   1594: |Thompson, Bob       | 11117.555|
                   1595: |Williams, Judy      | 11117.555|
                   1596: |Smythe, Carol       | 11117.555|
                   1597: |Hayes, Evelyn       | 11117.555|
                   1598: |Ross, Stanley       | 11117.555|
                   1599: |Smith, Paul         |  9687.000|
                   1600: |Williams, Bruce     |  9687.000|
                   1601: |-------------------------------|
                   1602: 
                   1603: continue
                   1604: *
                   1605: 
                   1606: .fi
                   1607: Suppose we wanted to find out
                   1608: how many people work for each
                   1609: manager, and in addition
                   1610: wanted only to include those
                   1611: employees who have worked at least seven years.
                   1612: .nf
                   1613: 
                   1614: * retrieve (e.manager,people=count(e.name by e.manager where
                   1615: * e.startdate < 1970))
                   1616: * \\g
                   1617: Executing . . .
                   1618: 
                   1619: 
                   1620: |manage|people       |
                   1621: |--------------------|
                   1622: |   199|            8|
                   1623: |    33|            2|
                   1624: |    32|            0|
                   1625: |    10|            0|
                   1626: |     0|            2|
                   1627: |    26|            2|
                   1628: |    55|            1|
                   1629: |   129|            2|
                   1630: |    13|            0|
                   1631: |--------------------|
                   1632: 
                   1633: continue
                   1634: *
                   1635: 
                   1636: .fi
                   1637: Notice that managers 32, 10, and 13 have
                   1638: no employees who started
                   1639: before 1970.  
                   1640: Now suppose we want to know the average
                   1641: salary for those employees.
                   1642: Simply change "count" to "avg" and rerun the query.
                   1643: .nf
                   1644: 
                   1645: * retrieve (e.manager,people=avg(e.salary by e.manager where
                   1646: * e.startdate < 1970))
                   1647: * \\g
                   1648: Executing . . .
                   1649: 
                   1650: 
                   1651: |manage|people    |
                   1652: |-----------------|
                   1653: |   199| 10882.250|
                   1654: |    33| 22687.000|
                   1655: |    32|     0.000|
                   1656: |    10|     0.000|
                   1657: |     0| 19533.500|
                   1658: |    26|  9542.000|
                   1659: |    55| 13621.000|
                   1660: |   129| 18771.000|
                   1661: |    13|     0.000|
                   1662: |-----------------|
                   1663: 
                   1664: continue
                   1665: *
                   1666: 
                   1667: .fi
                   1668: Notice what INGRES does for
                   1669: managers 32, 10 and 13.
                   1670: The average salary for those manager employees
                   1671: is actually undefined since there
                   1672: are no employees who started before 1970.
                   1673: INGRES always makes undefined values zero
                   1674: in aggregates.
                   1675: 
                   1676: If you want to remove the zero values from
                   1677: the output, a qualification can be added
                   1678: to the query.  
                   1679: The following query will find the average salaries
                   1680: only for those which are greater than zero.
                   1681: .nf
                   1682: 
                   1683: * retrieve (e.manager,people=avg(e.salary by e.manager where
                   1684: * e.startdate < 1970))
                   1685: * where avg(e.salary by e.manager where e.startdate < 1970) > 0
                   1686: * \\g
                   1687: Executing . . .
                   1688: 
                   1689: 
                   1690: |manage|people    |
                   1691: |-----------------|
                   1692: |   199| 10882.250|
                   1693: |    33| 22687.000|
                   1694: |     0| 19533.500|
                   1695: |    26|  9542.000|
                   1696: |    55| 13621.000|
                   1697: |   129| 18771.000|
                   1698: |-----------------|
                   1699: 
                   1700: continue
                   1701: * 
                   1702: 
                   1703: .fi
                   1704: Up until now we have been retrieving results directly
                   1705: onto the terminal.
                   1706: You can also save results by retrieving them into a
                   1707: new relation.
                   1708: This is done by saying:
                   1709: .nf
                   1710: 
                   1711:        retrieve into newrel ( ... )
                   1712:        where . . .
                   1713: 
                   1714: .fi
                   1715: The rules are exactly the same as for retrieves onto
                   1716: the terminal.
                   1717: INGRES will create the new relation with the
                   1718: correct domains, and then put the results
                   1719: of the query in the new relation.
                   1720: 
                   1721: For example, create a
                   1722: new relation called "overpaid" which has only
                   1723: those employees who make more than $8000:
                   1724: .nf
                   1725: 
                   1726: * retrieve into overpaid (e.all)
                   1727: * where e.salary > 8000
                   1728: * print overpaid
                   1729: * \\g
                   1730: Executing . . .
                   1731: 
                   1732: 
                   1733: overpaid relation
                   1734: 
                   1735: |number|name                |salary|manage|birthd|startd|
                   1736: |-------------------------------------------------------|
                   1737: |    10|Ross, Stanley       | 15908|   199|  1927|  1945|
                   1738: |    11|Ross, Stuart        | 12067|     0|  1931|  1932|
                   1739: |    13|Edwards, Peter      |  9000|   199|  1928|  1958|
                   1740: |    26|Thompson, Bob       | 13000|   199|  1930|  1970|
                   1741: |    32|Smythe, Carol       |  9050|   199|  1929|  1967|
                   1742: |    33|Hayes, Evelyn       | 10100|   199|  1931|  1963|
                   1743: |    37|Raveen, Lemont      | 11985|    26|  1950|  1974|
                   1744: |    55|James, Mary         | 12000|   199|  1920|  1969|
                   1745: |    98|Williams, Judy      |  9000|   199|  1935|  1969|
                   1746: |   129|Thomas, Tom         | 10000|   199|  1941|  1962|
                   1747: |   157|Jones, Tim          | 12000|   199|  1940|  1960|
                   1748: |   199|Bullock, J.D.       | 27000|     0|  1920|  1920|
                   1749: |   430|Brunet, Paul C.     | 17674|   129|  1938|  1959|
                   1750: |   843|Schmidt, Herman     | 11204|    26|  1936|  1956|
                   1751: |   994|Iwano, Masahiro     | 15641|   129|  1944|  1970|
                   1752: |  1330|Onstad, Richard     |  8779|    13|  1952|  1971|
                   1753: |  1523|Zugnoni, Arthur A.  | 19868|   129|  1928|  1949|
                   1754: |  1639|Choy, Wanda         | 11160|    55|  1947|  1970|
                   1755: |  4901|Bailey, Chas M.     |  8377|    32|  1956|  1975|
                   1756: |  5119|Ferro, Tony         | 13621|    55|  1939|  1963|
                   1757: |  5219|Williams, Bruce     | 13374|    33|  1944|  1959|
                   1758: |-------------------------------------------------------|
                   1759: 
                   1760: continue
                   1761: *
                   1762: 
                   1763: .fi
                   1764: On a "retrieve into" nothing is printed.
                   1765: We had to include a "print" command to see
                   1766: the results.
                   1767: Also, the relation name on a "retrieve into"
                   1768: must not already exist.
                   1769: For example, if we tried
                   1770: the same query again:
                   1771: .nf
                   1772: 
                   1773: * \\g
                   1774: Executing . . .
                   1775: 
                   1776: 5102: CREATE: duplicate relation name overpaid
                   1777: 
                   1778: continue
                   1779: *
                   1780: 
                   1781: .fi
                   1782: There are two special features about a "retrieve into".
                   1783: First, the result relation is automatically
                   1784: sorted and any duplicate tuples are removed.
                   1785: Second, the relation becomes part of
                   1786: the data base and is owned by you.
                   1787: If you don't want it to be saved you should
                   1788: remember to destroy it.
                   1789: The mechanism for destroying a relation will
                   1790: be mentioned a bit later.
                   1791: 
                   1792: So far we have only retrieved data but never
                   1793: changed it.
                   1794: INGRES supports three update commands:
                   1795: append, replace, and delete.
                   1796: 
                   1797: For example, to add "Tom Terrific" to the
                   1798: list of overpaid employees and start him
                   1799: off at $10000:
                   1800: .nf
                   1801: 
                   1802: * append to overpaid(name = "Terrific, Tom",salary = 10000)
                   1803: * \\g
                   1804: Executing . . .
                   1805: 
                   1806: 
                   1807: continue
                   1808: *
                   1809: 
                   1810: .fi
                   1811: Notice that we specified values for only two of the
                   1812: six domains in "overpaid".
                   1813: That is fine.
                   1814: INGRES will automatically set numeric domains
                   1815: to zero and character domains to blank, if
                   1816: they are not specified.
                   1817: 
                   1818: Notice also that INGRES did not print anything after
                   1819: the query.
                   1820: This is true for all update commands.
                   1821: 
                   1822: Let's give everyone in overpaid a 10% raise.
                   1823: To do this we want to replace o.salary by
                   1824: 1.1 times its value.
                   1825: Type the query:
                   1826: .nf
                   1827: 
                   1828: * range of o is overpaid
                   1829: * replace o(salary = o.salary * 1.1)
                   1830: * \\g
                   1831: Executing . . .
                   1832: 
                   1833: 
                   1834: continue
                   1835: *
                   1836: 
                   1837: .fi
                   1838: While the append command requires that you give a
                   1839: relation name (e.g. append to overpaid), the
                   1840: replace and delete commands require a
                   1841: tuple variable.
                   1842: Note that the command is:
                   1843: .nf
                   1844: 
                   1845:        replace o ( . . . )
                   1846:                where . . .
                   1847: 
                   1848: and not:
                   1849: 
                   1850:        replace overpaid ( . . . )
                   1851:                where . . .
                   1852: 
                   1853: .fi
                   1854: Print the results of these
                   1855: last two updates:
                   1856: .nf
                   1857: 
                   1858: * print overpaid
                   1859: * \\g
                   1860: Executing . . .
                   1861: 
                   1862: 
                   1863: overpaid relation
                   1864: 
                   1865: |number|name                |salary|manage|birthd|startd|
                   1866: |-------------------------------------------------------|
                   1867: |    10|Ross, Stanley       | 17498|   199|  1927|  1945|
                   1868: |    11|Ross, Stuart        | 13273|     0|  1931|  1932|
                   1869: |    13|Edwards, Peter      |  9899|   199|  1928|  1958|
                   1870: |    26|Thompson, Bob       | 14299|   199|  1930|  1970|
                   1871: |    32|Smythe, Carol       |  9954|   199|  1929|  1967|
                   1872: |    33|Hayes, Evelyn       | 11109|   199|  1931|  1963|
                   1873: |    37|Raveen, Lemont      | 13183|    26|  1950|  1974|
                   1874: |    55|James, Mary         | 13199|   199|  1920|  1969|
                   1875: |    98|Williams, Judy      |  9899|   199|  1935|  1969|
                   1876: |   129|Thomas, Tom         | 10999|   199|  1941|  1962|
                   1877: |   157|Jones, Tim          | 13199|   199|  1940|  1960|
                   1878: |   199|Bullock, J.D.       | 29699|     0|  1920|  1920|
                   1879: |   430|Brunet, Paul C.     | 19441|   129|  1938|  1959|
                   1880: |   843|Schmidt, Herman     | 12324|    26|  1936|  1956|
                   1881: |   994|Iwano, Masahiro     | 17205|   129|  1944|  1970|
                   1882: |  1330|Onstad, Richard     |  9656|    13|  1952|  1971|
                   1883: |  1523|Zugnoni, Arthur A.  | 21854|   129|  1928|  1949|
                   1884: |  1639|Choy, Wanda         | 12275|    55|  1947|  1970|
                   1885: |  4901|Bailey, Chas M.     |  9214|    32|  1956|  1975|
                   1886: |  5119|Ferro, Tony         | 14983|    55|  1939|  1963|
                   1887: |  5219|Williams, Bruce     | 14711|    33|  1944|  1959|
                   1888: |     0|Terrific, Tom       | 11000|     0|     0|     0|
                   1889: |-------------------------------------------------------|
                   1890: 
                   1891: continue
                   1892: *
                   1893: 
                   1894: .fi
                   1895: Let's fire whoever has the smallest salary:
                   1896: .nf
                   1897: 
                   1898: * delete o where o.salary = min(o.salary) \\g
                   1899: Executing . . .
                   1900: 
                   1901: 
                   1902: continue
                   1903: *
                   1904: 
                   1905: .fi
                   1906: Notice that the delete command requires
                   1907: a tuple variable (eg. delete o)
                   1908: and not a relation name.
                   1909: 
                   1910: What if we wanted to know who makes more that
                   1911: Tom Terrific?
                   1912: The query to do this is very subtle.
                   1913: First we use a new tuple variable called
                   1914: "t" which ranges over overpaid,
                   1915: and will be used to refer to Tom.
                   1916: t.name must equal "Terrific, Tom".
                   1917: Next, we use a tuple variable called "o"
                   1918: which will scan the whole relation.
                   1919: If we ever find an o.salary > t.salary
                   1920: then o.name must make more than Tom.
                   1921: 
                   1922: The complete query is:
                   1923: .nf
                   1924: 
                   1925: * range of t is overpaid
                   1926: * retrieve (o.name, osal=o.salary, tomsal = t.salary)
                   1927: * where o.salary > t.salary
                   1928: * and t.name = "Terrific, Tom"
                   1929: * \\g
                   1930: * Executing . . .
                   1931: 
                   1932: 
                   1933: |name                |osal  |tomsal|
                   1934: |----------------------------------|
                   1935: |Ross, Stanley       | 19247| 11000|
                   1936: |Ross, Stuart        | 14600| 11000|
                   1937: |Thompson, Bob       | 15728| 11000|
                   1938: |Hayes, Evelyn       | 12219| 11000|
                   1939: |Raveen, Lemont      | 14501| 11000|
                   1940: |James, Mary         | 14518| 11000|
                   1941: |Thomas, Tom         | 12098| 11000|
                   1942: |Jones, Tim          | 14518| 11000|
                   1943: |Bullock, J.D.       | 32668| 11000|
                   1944: |Brunet, Paul C.     | 21385| 11000|
                   1945: |Schmidt, Herman     | 13556| 11000|
                   1946: |Iwano, Masahiro     | 18925| 11000|
                   1947: |Zugnoni, Arthur A.  | 24039| 11000|
                   1948: |Choy, Wanda         | 13502| 11000|
                   1949: |Ferro, Tony         | 16481| 11000|
                   1950: |Williams, Bruce     | 16182| 11000|
                   1951: |----------------------------------|
                   1952: 
                   1953: continue
                   1954: * 
                   1955: 
                   1956: .fi
                   1957: If we wanted to give Tom Terrific $50 more
                   1958: than anyone else, the query would be:
                   1959: .nf
                   1960: 
                   1961: * replace o(salary = max(o.salary) + 50)
                   1962: * where o.name = "Terrific, Tom"
                   1963: * \\g
                   1964: Executing . . .
                   1965: 
                   1966: 
                   1967: continue
                   1968: * 
                   1969: 
                   1970: .fi
                   1971: Finally, to destroy a relation owned by
                   1972: yourself, type the command:
                   1973: .nf
                   1974: 
                   1975: * destroy overpaid
                   1976: * \\g
                   1977: Executing . . .
                   1978: 
                   1979: 
                   1980: Continue
                   1981: *
                   1982: 
                   1983: .fi
                   1984: We are now ready to leave INGRES.
                   1985: This is done either by typing
                   1986: an end-of-file (control/d)
                   1987: or more typically use the "\\q"
                   1988: command:
                   1989: .nf
                   1990: 
                   1991: * \\q
                   1992: INGRES vers 6.1/0 logout
                   1993: Tue Aug 30 14:55:20 1977
                   1994: goodbye bob -- come again
                   1995: .fi

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.