|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.