===== CS 325 - Week 11 Asynchronous Material ===== ===== "TODAY" WE WILL ===== * announcements * continuing converting model into a design/schema, part 2 * SQL: mention the ANSI syntax for joins * SQL: demo of some more-than-two-table-joins * SQL: intro to views * [IF time:] SQL: intro to sequences * prep for next class * Reading: * DB Reading Packet 8 - Database Design, Part 2 * SQL Reading Packet 7 - has the view material (but Sequences are in SQL Reading Packet 6, and where are those more-than-2-table join examples...?) * Should be working on Homework 8, due by 11:59 pm on Friday * Should be working on converting your Project model draft into a Project design draft (due November 19th) * (and have your talked to your academic advisor about Spring 2022 registration? 8-) ) ===== MORE odds-and-ends that you might encounter in converting a database model into a database design/schema ===== FIRST: handling so-called ASSOCIATION entity classes ===== * sometimes you find, in a model, an entity class that ASSOCIATES two or more other entity classes in a transaction that is pretty important to the scenario, * AND has attributes of its own, * BUT does not have reasonable/apparent identifying attributes. * Consider the Flight model we showed on the recording -- We might get "base" tables for entity classes Flight and Customer of: Flight(FLIGHT_NUM, flight_date, exp_departure, exp_arrival, actl_departure, actl_arrival) Customer(CUST_NUM, cust_lname, cust_fname) * Flight_reservation, here, is an example of an association entity class; we'll start a "base" table for it: Flight_Reservation( ...but what should its primary key be? * what MIGHT be different here? you sometimes have TWO reasonable choices for the primary key of association entity class Flight_reservation; * one choice: to introduce a primary key for that association in the flight model, you might introduce a reserv_num as a primary key for Flight_reservation: Flight_Reservation(RESERV_NUM, reserv_date_made, flight_num, cust_num) foreign key(flight_num) references Flight, foreign key(cust_num) references Customer * another choice: OR it might "feel" more appropriate, for many association entity classes, to consider thre association entity to be identified by the identifiers of the entities it is associating; that is, maybe I'd rather identify a flight reservation by the customer reserving for the flight and the flight that customer is making a reservation for; In this approach, the foreign keys, combined, are made the primary key of the association entity class' "base" table: Flight_Reservation(reserv_date_made, FLIGHT_NUM, CUST_NUM) foreign key(flight_num) references Flight, foreign key(cust_num) references Customer * another classic association entity class: sale_item_quant, associating a sale and a sale_item with JUST the attribute quantity, the quantity of THAT sale item in THAT sale This is a pretty classic case where you might choose not to intro a separate primary key for sale_item_quant's "base" table -- Sale_item_quant(SALE_NUM, SKU_NUM, quantity) foreign key(sale_num) references Sale, foreign key(sku_num) references Sale_item * what's another case where you might use a foreign key from a relationship line as part or all of another table's primary key? you MIGHT do so for handling weak entity classes (since they are so dependent on another entity class, and are usually related to that entity class as the child in a 1:N relationship or in 1:1 relationship where that relationship is REQUIRED on its end) * consider a scenario with multiple apartment buildings, they want to keep track of, for each room in one, its room number, num of bedrooms, and num of baths, but maybe that's it; Room_num cannot be the Room entity class "base" table's primary key, because there might be, say, a room 101 in more than one apartment building; * You know you WILL be adding bldg_num to Room's "base" table because 1:N relationship contains; Room(ROOM_NUM, num_bedrooms, num_baths, BLDG_NUM) foreign key(bldg_num) references Apt_Bldg ...so the weak entity class' "base" table's primary key may be a COMBO of one of its attributes AND the primary key of the "base" table of the entity class it is dependent upon; ===== What about RECURSIVE relationships? ===== * consider Employee-manages-Employee -- and it is 1:N; still put the "parent's" "base" table's primary key into the "child's", as a foreign key, BUT they're the same "base" table (!!!), so the foreign key needs a different name, suggesting the relationship: Employee(EMPL_NUM, mgr_num foreign key(mgr_num) references Employee(empl_num) * populating this can be fun! if you have an employee with NO manager, insert their row first! (With NULL for mgr_num)! THEN you can insert employees managed by THAT employee, THEN you can insert employees managed by any of THOSE employees, and so on! (typically only annoying for the FIRST insertions...!) * by the way: what if the foreign key cannot be null? ...you might need to create the table with a foreign key that can be null, insert a first row with mgr_num as null, THEN add a second row that manages them, and so on, THEN use update commands to UPDATE their foreign keys to now-existing rows, THEN use an ALTER command to make the foreign key column NOT NULL...! a kluge, but it can work!! ===== MULTIPLE relationships between entity classes ===== * still handle each individually! BUT!! you may need to be creative/descriptive with the table names, OR you may need a renamed foreign key, depending on the cardinalities of the relationships involved; * if 2 M:N relationships? JUST give them different intersection table names! Member(MEM_NUM,.... Talk(TALK_NUM, .... In_charge(MEM_NUM, TALK_NUM) foreign key(mem_num) references Member, foreign key(talk_num) references Talk Sign_Ups(MEM_NUM, TALK_NUM) foreign key(mem_num) references Member, foreign key(talk_num) references Talk * BUT -- what about the music prof advises and gives lesson to students situation? * Student needs Music_prof's foreign key TWICE -- so NAME both foreign keys to make CLEAR which relationship they are for; Student(STU_NUM, advisor_num, private_tch_num, foreign key(advisor_num) references Music_prof(prof_num), foreign key(private_tch_num) references Music_prof(prof_num) ======== SQL "ANSI" join syntax ======== from https://en.wikipedia.org/wiki/SQL: * "SQL became a standard of the American National Standards Institute (ANSI) in 1986, and of the International Organization for Standardization (ISO) in 1987." * ANSI SQL/99 included some additional ways to express different join operations; ...here's one of those syntaxes: select expr1, expr2, ..., exprN from tbl1 JOIN tbl2 ON (tbl1.attrib1 = tbl2.attrib2); this, then, is a reasonable alternative to saying: select expr1, expr2, ..., exprN from tbl1, tbl2 where tbl1.attrib1 = tbl2.attrib2; * AND maybe you'll be less likely to forget the JOIN condition using the ANSI join syntax!! 8-) * FEEL free to use the above -- it is FINE, good style!!!! (BUT the ANSI "natural join" syntax does NOT meet class style standards -- that's a DIFFERENT syntax than either one above!!) ====== joining MORE than TWO tables! ====== * JUST REMEMBER: when you join N tables, you need to have (N-1) appropriate join conditions!!!!!!!! what if you want: the name of a customer, the name of the employee who represents them, and the name of the department that employee works for? select cust_lname, empl_last_name, dept_name from customer c, empl e, dept d where c.empl_rep = e.empl_num and e.dept_num = d.dept_num; HERE is that query in ANSI join notation: select cust_lname, empl_last_name, dept_name from customer c JOIN empl e ON c.empl_rep = e.empl_num JOIN dept d on e.dept_num = d.dept_num; ====== intro to SQL views ====== * a view is a "derived" table -- it is NOT actually stored in rows in the database (or in a data structure containing the actual data) -- instead, a view in a DBMS JUST contains HOW to generate the desired information when the view is used! (the user can USE it like it was a table, but whenever it is used, it is generated at that point!) * you can have a view for a "tabular" beastie users want to refer to but that would be problematic in terms of modification anomalies -- or just makes certain other queries more convenient AND you can have a view when you want to restrict someone's access to just SOME of the rows of some table (you can grant access to a view instead of the whole table the view is based on) * here's the basic syntax: create view view_name as desired_select_statement; * NOW a few more nuances here: * you can rename the columns in the view in a couple of ways, and sometimes you HAVE to...! * that is -- the view "looks" like a table to users and programmers, who can use it like a table in select statements, SO its column names HAVE to meet SQL's column name syntax; (so, for a view based on an aggregate function call or computation, you HAVE to rename those columns! METHOD ONE: * use column aliases in the select statement! create view short_empl2 as select empl_last_name last_name, job_title job from empl; * (note: now, using the view short_empl2, ONLY the column names last_name and job are known! drop view salary_avgs; create view salary_avgs as select job_title, avg(salary) job_avg_salary from empl group by job_title; METHOD TWO: * put the desired column names IN a comma-separated list IN parentheses AFTER the view's name in the create view statement (but you must give a name for EACH column in this version): drop view salary_avgs2; create view salary_avgs2(job_title, job_avg_salary) as select job_title, avg(salary) from empl group by job_title; ...and that should be enough for you to try out views in Friday's lab exercise and the next homework assignment!