Annotation of 42BSD/ingres/doc/other/tutorial.nr, revision 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.