22 JUL
Focus block I · design and normalization
ec_order from Additional Exercise 2 and write the five-table copy order.48-hour focus · paper-first preparation
A source-aligned exam studybook for recognizing the question type, choosing the method, showing just enough working, and checking the result without a calculator.
Separate known exam facts from inference so your preparation is aggressive without pretending there is evidence that is not here.
LearningLabWrapUp.pdf is the strongest local match because it is the integrated lab under Exam Preparation.Priorities therefore use the instructor’s dated focus, the mock-equivalent lab inference, and recurrence across homework and labs—not invented “past-exam frequency.”
This late evidence overrides the earlier priority order. It confirms what deserves the remaining study time; it does not remove any semester topic from scope.
| Verdict | Topic / source | What to do now |
|---|---|---|
| FOCUS ★ | Normalization | Do closure, candidate-key proof, 1NF→BCNF verdict, and decomposition from Homework 06, Learning Lab 07, and Additional Exercise 2. |
| FOCUS ★ | ERM | Draw entities, attributes, both cardinalities, and relationship attributes from Homework 03, Learning Labs 03–04, and Wrap-Up Task 1. |
| FOCUS ★ | Relational Model | Map 1:N, 1:1, M:N, recursive, and multivalued constructs; show PKs and FKs explicitly. |
| FOCUS ★ | Relational Algebra | Solve Learning Lab 06 on paper, including intermediate/result tuples—not expression-only answers. |
| FOCUS ★ | SQL | Write joins, aggregates, HAVING, zero-preserving counts, and anti-joins from Homework 08, Learning Lab 09, and Wrap-Up Task 5. |
| IN | All other semester topics | Retain short knowledge recall after the five focus areas. Nothing was ruled out. |
| MOCK-EQUIVALENT | A specific iLearn learning lab | Use the local Wrap-Up lab as the rehearsal unless iLearn shows a different title; the email itself does not identify it. |
“You can find a specific learning lab in iLearn is comparable to a mock exam.”
“Furthermore, all the topics we were discussing about during the semester are relevant.”
“However, the focus is on topics that were included in the learning labs and homework sheets.”
“Normalization, ERM, SQL, Relational Model, Relational Algebra are hence the focus.”
Received 22 July 2026 in reply to Alex’s 21 July request for a mock exam, main examinable areas, and expected working. Wording is preserved; greeting, signature, and contact details are omitted as administrative material.
Two study days remain before Friday’s exam. The order follows the instructor’s 22 July focus; “safe to skip” applies only after every must-do block.
ec_order from Additional Exercise 2 and write the five-table copy order.cheatsheet.html from memory, check it, then leave it at home. Spend 30 minutes on Chapter 6 knowledge recall because all semester topics remain relevant.Every exam question type, worked on a real exercise. Each drill: the basics in plain words → the real exercise → what to look at → exactly what to write → why it works.
Read this chapter first. The later chapters are the reference; this one is the training. Nothing here assumes you already know the vocabulary—each drill starts by building it.
🔴 Exam-core Prof. Scholz explicitly named ERM as a focus on 22 July 2026; it is drilled in Homework 03, Learning Labs 03–05, and Wrap-Up Task 1.
An ER model is a picture of what the database will store, drawn before any table exists. Chen notation uses exactly four things:
How to read cardinality without confusing yourself. Always ask the question twice, once from each side, and write the answer at the far end:
If both answers are “many”, it is M:N and you will later need a third table. If both are “one”, it is 1:1 and is rare. Most links are 1:N.
Write this — the exam answer
Draw it. If you also want words beside the drawing, this is all that is needed:
Why — the full explanation
Why Department is its own entity and not an attribute of Employee. A department has its own ID and its own name, and many employees share it. Anything with its own identifier that repeats across rows is an entity. If you made it a text attribute on Employee you would store the same department name hundreds of times — the exact problem normalization exists to prevent.
Why “is head of” is 1:1. The text says a department has “a person who is the head”. One head per department; and a person heads at most one department. Both directions answer “one”, so 1:1. This is a separate relationship from “works for” even though both connect Employee and Department — they mean different facts, so they get their own diamonds. Two entities may be joined by several relationships.
Why “is boss of” loops back to Employee. A boss is an employee. Drawing a second box called “Boss” would duplicate the same people. Instead the line leaves Employee and returns to Employee. Cardinality: one employee can boss many (N), and each employee has one boss (1). When you translate this to tables later, it becomes a boss_id column inside Employee pointing at Employee.
Why specialization rather than three entities. Producers and retailers are companies — they share CompanyID, Name, LegalForm — and only add one attribute each. Specialization says “same thing, extra detail”. Two independent entities would force you to duplicate the shared attributes. In the exam, draw the supertype on top, an “is a” connector, and the two subtypes below with only their extra attributes.
Task 2 — what changes when dates arrive. “An employee belongs to a department from some start date to an end date” means the fact now has its own properties. A fact’s properties hang off the diamond, not off either entity: StartDate and EndDate become attributes of the relationship. Do this for all three relationships the task lists. And note the consequence: once a relationship carries dates, the same employee can appear in it more than once, so it stops being a plain 1:N link and behaves like M:N over time.
🔴 Exam-core Prof. Scholz explicitly named the Relational Model as a focus on 22 July 2026; Wrap-Up Tasks 2–4, Learning Labs 05 and 08, and Homework 07 drill it.
Turning a picture into tables is mechanical. There are only three cases, decided by the cardinality you already wrote:
Vocabulary you need: a primary key is the column(s) that identify a row uniquely — never repeated, never empty. A foreign key is a column holding a primary key value from another table; it is how tables are linked, and the database refuses values that do not exist over there.
Write this — the exam answer
Then the DDL, one table per relation, parents before children. This version uses the short, common PostgreSQL spelling varchar and puts each one-column foreign key directly on its column:
CREATE TABLE hm_hotel ( ho_id integer PRIMARY KEY, ho_name varchar(255) NOT NULL, ho_street varchar(255) NOT NULL, ho_house_number varchar(50) NOT NULL, ho_zip_code varchar(50) NOT NULL, ho_city varchar(255) NOT NULL ); CREATE TABLE hm_type ( ty_id integer PRIMARY KEY, ty_name varchar(255) NOT NULL UNIQUE, ty_description varchar(255), ty_price numeric(10,2) NOT NULL CHECK (ty_price >= 0) ); CREATE TABLE hm_room ( ro_id integer PRIMARY KEY, ro_hotel integer NOT NULL REFERENCES hm_hotel(ho_id), ro_type integer NOT NULL REFERENCES hm_type(ty_id), ro_living_area numeric(10,2) NOT NULL CHECK (ro_living_area > 0) ); CREATE TABLE hm_guest ( gu_id integer PRIMARY KEY, gu_name varchar(255) NOT NULL, gu_street varchar(255) NOT NULL, gu_house_number varchar(50) NOT NULL, gu_zip_code varchar(50) NOT NULL, gu_city varchar(255) NOT NULL ); CREATE TABLE hm_booking ( bo_room integer REFERENCES hm_room(ro_id), bo_guest integer REFERENCES hm_guest(gu_id), bo_start_date date, bo_end_date date NOT NULL, PRIMARY KEY (bo_room, bo_guest, bo_start_date), CHECK (bo_end_date > bo_start_date) );
Why — the full explanation
Why Room swallowed two foreign keys. Both “includes” (Hotel–Room) and “is of” (Room–Type) are 1:N with Room on the N side. Rule 1 fires twice: the key of the 1 side goes into the N side. So Room gains HotelID and TypeID, and the two relationships vanish as separate tables. This is what “refine the relational model” means in Task 2 — the first draft lists Includes and IsOf as tables, and refining folds them away.
Why Booking survived as a table. A guest books many rooms and a room is booked by many guests — M:N. There is no single column you could add to either side without repeating rows. So it becomes its own table and the dates from the diamond live there. Because the prompt explicitly allows the same guest to book the same room at different dates, the occurrence key is (bo_room, bo_guest, bo_start_date).
Why this foreign-key form is easier. ro_hotel integer NOT NULL REFERENCES hm_hotel(ho_id) says the whole rule from left to right: column name → type → mandatory → referenced table/key. It creates the same foreign-key constraint as the longer table-level CONSTRAINT … FOREIGN KEY … REFERENCES … form. Use the long form only when the FK has several columns, you must give the constraint a specific name, or you need a more elaborate table-level declaration.
varchar is the short spelling. In PostgreSQL, varchar(n) and character varying(n) are synonyms. The numbers 50 and 255 are common, memorable conventions—not special presets and not normal-form rules. Here 50 is ample for compact address parts such as house number and postal code; 255 is a simple shared cap for names, streets, cities, and descriptions. If the requirements give no meaningful maximum, PostgreSQL text is also valid.
Why integer and NOT NULL. The exercise explicitly asks for integer primary keys and supplies the ID values, so plain integer PRIMARY KEY is the easiest exam answer. NOT NULL on ro_hotel encodes a modelling fact: a room cannot exist without a hotel. The three BOOKING key columns are automatically NOT NULL because they form its primary key.
Why order matters. A foreign key can only point at a table that already exists, so create Hotel and Type before Room, and Room and Guest before Booking. If the exam asks only for one table, say which tables it depends on.
Correction to the supplied answer. Its hm_books primary key is only (bo_room, bo_guest), which silently forbids the repeated-date case stated in Task 1. The exam-faithful answer is the three-column key above. Name the prompt sentence as justification; do not copy a key that contradicts it.
StartDate—in the bridge key.Easy inline FK: child_id integer NOT NULL REFERENCES parent(parent_id). Use table-level FOREIGN KEY mainly for composite or specially named constraints.
Repeatable event key = participant FKs + occurrence discriminator; here BOOKING(room_id,guest_id,start_date) → end_date.
Write this — the exam answer
State the semantic FDs and candidate keys first. We infer dependencies from the prompt, not from accidental repetition in the twelve sample rows.
| Relation | Candidate key | Non-trivial functional dependency |
|---|---|---|
| HOTEL | HotelID | HotelID → Name, Street, HouseNumber, ZipCode, City |
| TYPE | TypeID | TypeID → Name, Description, Price |
| ROOM | RoomID | RoomID → HotelID, TypeID, LivingArea |
| GUEST | GuestID | GuestID → Name, Street, HouseNumber, ZipCode, City |
| BOOKING | RoomID, GuestID, StartDate | (RoomID, GuestID, StartDate) → EndDate |
The source row “Rooms = 1, 2, 3” becomes three ROOM rows linked by HotelID. Address is split into the fields shown by the ER model; BookingPeriod becomes StartDate and EndDate. Every cell is now one value from one domain.
HOTEL, TYPE, ROOM, and GUEST have one-attribute keys, so a proper key subset does not exist. BOOKING has one non-key fact, EndDate, and it depends on the complete occurrence key—not RoomID alone, GuestID alone, or the participant pair.
Hotel facts live only in HOTEL, type description/price only in TYPE, room facts only in ROOM, and guest facts only in GUEST. BOOKING stores no copied hotel, type, price, or guest address. Therefore no non-key attribute determines another non-key attribute.
Each non-trivial FD above starts at the relation’s key. Therefore all five relations are already in BCNF; normalization requires no further split.
Final verdict: the corrected relational model is in BCNF (therefore also 3NF, 2NF, and 1NF) under the stated FDs.
Why this is a proof, not a guess
Normalization can finish without decomposing again. The ER-to-relational mapping has already separated the determinants: TypeID fixes the type’s price in TYPE rather than repeating Price in ROOM or BOOKING, and HotelID fixes hotel facts in HOTEL rather than copying the address into every room.
Do not invent ZipCode → City. Postal codes are not globally unique without a country/context, and the prompt never declares that dependency. Likewise the sample happens to show one row per type name, but Name is an alternate key only if the design explicitly makes it UNIQUE. If it is declared UNIQUE, it is still a candidate key, so TYPE remains BCNF.
The booking key controls the 2NF argument. With the supplied two-column key, a second booking of the same room by the same guest cannot exist at all. With the corrected occurrence key, EndDate is a fact about that full occurrence.
Hotel proof: IDs determine their own facts; (room,guest,start)→end; scalar cells, no partial/transitive FDs, and every determinant is a key ⇒ BCNF.
Write this — the complete paper answer
Assumption: the current PostgreSQL connection is to database lecture.
-- current database: lecture CREATE SCHEMA invoiceschema; CREATE TABLE invoiceschema.customer ( cu_id integer PRIMARY KEY, cu_firstname varchar(255) NOT NULL, cu_lastname varchar(255) NOT NULL, cu_city varchar(255) NOT NULL ); CREATE TABLE invoiceschema.invoice ( in_id integer PRIMARY KEY, in_customer integer NOT NULL REFERENCES invoiceschema.customer(cu_id), in_items integer NOT NULL CHECK (in_items > 0), in_date date NOT NULL, in_amount numeric(10,2) NOT NULL CHECK (in_amount >= 0) );
If Task 1.1 treated the full customer name as one atomic display value, replace the first-name and last-name columns with cu_name varchar(255) NOT NULL. The schema commands do not change.
What “schema” means here
It is not the same as a relational schema. A relational schema is a table description such as INVOICE(IID,CID,Items,Date,Amount). A PostgreSQL schema is a named namespace inside one database, used to group and qualify objects.
How the database part works. PostgreSQL cannot create an object “in another database” from the current connection. In pgAdmin, open the Query Tool under lecture. In psql, connect with \connect lecture first; that line is a psql command, not SQL. On paper, the comment -- current database: lecture is enough unless the question explicitly asks for psql commands.
Why the table names include the schema. Writing invoiceschema.customer proves where the table goes and needs no SET search_path. The equivalent alternative is SET search_path TO invoiceschema; followed by unqualified CREATE TABLE customer ....
Correction to the supplied solution. It shows the two CREATE TABLE statements but omits both CREATE SCHEMA invoiceschema and schema qualification. Unless the search path had already been changed, that code would normally create the tables in public, not in the requested schema.
PostgreSQL namespace: connect to database d → CREATE SCHEMA s; → CREATE TABLE s.parent(...); → CREATE TABLE s.child(... REFERENCES s.parent(id));
🔴 Exam-core Prof. Scholz explicitly named Normalization as a focus on 22 July 2026; Homework 06, Learning Lab 07, Additional Exercise 2, and the Wrap-Up require it.
Functional dependency (FD). Written X → Y, read: “if I know X, then Y is fixed.” That is the whole definition. Test it on the data: pick two rows with the same X — if Y ever differs, it is not an FD.
Candidate key. A set of columns that (a) determines every other column, and (b) cannot be made smaller. Find it by asking: what is the fewest columns I need to pin down one row?
Prime attribute = a column that is part of some candidate key. Non-prime = everything else. You need the word for the 2NF test.
Now the four checks, in order. Each one assumes the previous passed — if 1NF fails, everything below fails automatically.
X → Y, X must be a superkey. Stricter than 3NF.Use the same classroom workflow every time: first write the atomic 1NF relation and its key; use its partial dependencies to build 2NF; use the 2NF relations’ transitive dependencies to build 3NF; then test every resulting relation for BCNF. If a stage needs no split, copy the relations forward and write “unchanged”—do not jump silently from the source table to the final design.
How one split works: take the FD that broke the current stage, put its determinant and dependants in a new relation with the determinant as key, and retain the determinant in the remaining relation as a foreign key. Nothing is deleted; the facts get one clear home.
These lines are relational-schema shorthand, not SQL. The arrow has two related but different readings depending on where it appears.
{City, Attraction} is a set of attributes. Braces group the columns; their order is irrelevant.City → Country is an FD: equal City values must have equal Country values. Read the arrow as “determines.”Country⁺ is the closure of Country: everything obtainable from Country using the FDs.X⁺ contains every attribute, X is a superkey. If no proper subset of X still works, X is a candidate key.CITY(City, Country, …) means a relation/table named CITY with the listed attributes/columns.City PK means City is the chosen primary key — one selected candidate key.Country FK→COUNTRY.Country means CITY.Country is a foreign key referencing COUNTRY.Country. Here the arrow means “references.”PK(CITY_ATTRACTION)={City, Attraction} means the pair is one composite primary key; neither attribute is claimed to be a key alone.Paper rule: use either underlining or explicit PK/FK labels, and stay consistent. When the referenced primary key is obvious, Country FK→COUNTRY is an acceptable shorter form.
Write this — the exam answer
Classroom working example · build every stage
The original answer above is already correct. The sequence below expands its decomposition into the 1NF → 2NF → 3NF → BCNF working used in class.
Every cell is atomic. Candidate key: (StudentID, Unit).
Name and Gender now depend on the whole key of STUDENT; Grade depends on the whole composite key of STUDENT_UNIT.
STUDENT and STUDENT_UNIT are already in 3NF.
StudentID is a key of STUDENT; (StudentID, Unit) is a key of STUDENT_UNIT. Every determinant is therefore a superkey of its own relation.
Final BCNF design: STUDENT(StudentID, Name, Gender) and STUDENT_UNIT(StudentID, Unit, Grade).
Why — the full explanation
Why the key is the pair. One row is one grade. To point at exactly one grade you must say which student and which unit — student 101 has three grades, and “Mathematics” is taken by several students. Neither column alone is enough, and together they are enough, so {StudentID, Unit} is minimal and therefore a candidate key.
Why Name → StudentID is not an FD. Tempting, because names look identifying. But the prose warns you: Fred is 101 and Fred is also 106. Two rows share a Name and disagree on StudentID, so the dependency fails. This is exactly why the prose is printed — it is not decoration.
What “partial dependency” actually means. The key has two parts. Gender is decided by only one of them. So if student 102 takes four units, her Name and Gender are copied into four rows. That duplication is the disease; 2NF is the rule that names it. Split so each fact is stored once: identity facts in Student, performance facts in StudentUnit.
Separate the source verdict from the repaired design. The original 1NF relation is not in 2NF, so that original relation is also not in 3NF or BCNF. After the 2NF split, however, the new relations pass 3NF and BCNF. Write both facts; “not 3NF” describes the starting table, while “final design is BCNF” describes the result.
Check your decomposition is lossless. The two new tables share StudentID. Joining them back on StudentID reproduces the original rows exactly, with nothing invented and nothing lost. That shared column is the test: if the pieces had no column in common, the split would be wrong.
NF working: write 1NF schema+key → split partial FDs for 2NF → split transitive FDs for 3NF → in each relation, every determinant must be a key for BCNF.
Write this — the exam answer
Classroom working example · build every stage
The original answer above is the concise solution. The sequence below shows how to arrive at those final relations one normal form at a time.
Attractions contains lists such as “Louvre, Eiffel Tower”. Build one row per attraction.
Candidate key after the explosion: (City, Attraction).
Every non-prime attribute now depends on the whole key of its relation.
Country, City, and (City, Attraction) are keys of their respective relations, so every non-trivial determinant is a superkey.
Final BCNF design: COUNTRY, CITY, and CITY_ATTRACTION as shown above.
Why — the full explanation
The 1NF break is the visible one. “Louvre, Eiffel Tower” is two facts in one cell. You cannot search, count, or delete one attraction without string surgery. The fix is a row per attraction, which is why Attractions becomes its own table and the key of that table is the pair {City, Attraction}.
The 3NF break is the one people miss. CountryPopulation is a fact about the country, not about the city. The chain is City → Country → CountryPopulation: a non-key column determined by another non-key column. Consequence: France’s population is written three times (Paris, Lyon, Marseille), and correcting it means finding every row. Pull it into a Country table and store it once.
Why the key changes after the 1NF fix. Before the fix, one row per city, so {City} identifies it. After splitting attractions into their own rows, a city appears several times in that table, so you need City plus Attraction to pin one row. This is worth a sentence in the exam — the official answer states both keys.
Why Capital stays in City. Capital is yes/no for that city. It genuinely depends on City, not on Country, so it belongs in the City table. (You could argue Country → capital-city, but the column as written describes the city.)
Repeating group → one 1NF row per value and recompute key; then City-only facts → CITY, CountryPopulation → COUNTRY, pair fact → CITY_ATTRACTION.
With no story to reason about, use the algorithm. The closure of a set X, written X⁺, is everything you can reach by repeatedly applying the FDs.
Stop as soon as a set reaches all six letters, and never test a superset of something that already worked (keys must be minimal).
Write this — the exam answer
Worked BCNF example · optional extension
Task 3.2 asks only for the BCNF verdict. The cards below keep that original answer intact and show one independently checked lossless BCNF attempt as extra practice.
A → B is one sufficient counterexample: A+ = AB, not all attributes.
Every decomposition step is lossless. This extension is not required by Task 3.2.
Exam stopping point: “Not in BCNF because A → B and A is not a superkey.”
Why — the full explanation
Why start with “what never appears on the right”. If a letter is never produced by any FD, no combination of other letters can ever give it to you — so it must be handed to you in the key itself. C and E qualify, which instantly shrinks the search from 63 possible subsets to a handful. This trick alone usually finds the keys in under a minute.
Why three keys and not one. Once you have C and E, you need something that eventually yields A, B and D. Adding A works (A→B, then BC→D). Adding B works (BC→D, then CD→A). Adding D works (CD→A, then A→B). Three different minimal ways in, so three candidate keys — all equally valid.
Why it fails 2NF, not merely BCNF. Take AE→F. The candidate key containing A and E is ACE. AE is a proper part of it, and F is non-prime (F is in no key). A non-prime attribute depending on part of a key is precisely the 2NF violation. Naming the specific FD and the specific key is what earns the mark — “it is not in BCNF” alone does not.
Why the optional BCNF result is labelled carefully. The source asks only for the verdict. The generated decomposition CEF, AB, ACD, CDE is lossless and every result is in BCNF, but it does not preserve BC→D and AE→F as constraints that can be checked inside one table. BCNF can sacrifice dependency preservation; say so if you volunteer the decomposition.
BCNF failure proof: name X→Y, show X⁺ ≠ all attributes. A lossless BCNF split can lose dependency preservation—check both properties separately.
🔴 Exam-core Prof. Scholz explicitly named Relational Algebra as a focus on 22 July 2026; it is drilled in Homework 05 and Learning Lab 06.
Relational algebra is SQL with mathematical notation. Each operator takes relations in and gives a relation out, so you can nest them. The first six operators are classical; counting, totals, outer joins, and ordering use named extended operators.
| Symbol | Name | Plain meaning | SQL equivalent |
|---|---|---|---|
| σ sigma | selection | keep the rows that match a condition | WHERE |
| π pi | projection | keep the columns you list (drops duplicates) | SELECT DISTINCT |
| ⋈ | join | glue two tables where a condition matches | JOIN … ON |
| − | difference | in the first, not in the second | NOT IN / EXCEPT |
| ∩ ∪ | intersect / union | in both / in either | INTERSECT / UNION |
| γ gamma | group / aggregate | one group per listed key; compute COUNT, SUM, … | GROUP BY + aggregate |
| ⟕ | left outer join | keep every left row, even without a match | LEFT JOIN |
| τ tau | sort | order the result; ↓ means descending | ORDER BY … DESC |
Exam-safe notation note. Classical relational algebra is unordered and has no COUNT or SUM. Therefore Wrap-Up 5.1.2 needs extended τ for its requested order, while 5.2.2 and 5.3.2 need extended γ. State “extended relational algebra” beside those answers; if the examiner permits only the classical core, write the relational part and explicitly say which requested operation is outside it.
The one habit that makes these easy: read the expression from the inside out, and build it in this order —
Subscripts. The condition rides under the symbol: σPlaces=2(Room). The join condition rides under the bowtie: A ⋈A.x=B.x B. When two tables both have a “Name” column, write the table in front: Student.Name.
Write this — the exam answer
Why — the full explanation
1.1 needs no join because Study and Name are both inside Student. Whenever every column mentioned lives in one table, the answer is just π(σ(table)) — do not add joins for decoration.
1.2 and 1.3 are the standard shape. The filter applies to one table, then you join to reach the column you must display. Note the σ sits inside the join: filter Room down to the 2-place rooms first, then join. Filtering before joining is both cheaper and easier to write.
Why 1.4 needs ∩ and not a single σ with “and”. The condition is about two different rows of Examines — one exam for Operations Research, another for Information Systems. A single row can never satisfy Title='OR' ∧ Title='IS'; that would return nothing. So compute the set of students who passed the first course, compute the set who passed the second, and intersect. This is the standard trick whenever a prompt says “both X and Y” about repeated facts.
Why 1.5 uses difference and then joins back. “Students that do not attend courses” is an absence, and algebra expresses absence with −. Take all Student# and subtract the Student# that appear in Attends; what remains are the non-attenders — but only their IDs. The prompt asks for names, so join that set back to Student to pick up the Name column. Forgetting the join back is the most common error here.
Why 1.6 puts both conditions in one σ. Semester and Grade describe the same exam row, so a single selection with ∧ works. Then two joins bring in the student’s name and the lecture’s title, and the final π shows both columns as asked.
Reading trees in general. Leaves are tables; you evaluate upward; each node consumes what is below it. If asked for “the resulting relation”, give the actual rows, not a description — check them against the printed data.
🔴 Exam-core Prof. Scholz explicitly named SQL as a focus on 22 July 2026; Homework 08, Learning Lab 09, Wrap-Up 5, and Additional 4 are query sets.
A SELECT has at most six clauses and they must appear in this order. You can memorise the skeleton and fill the blanks:
The single most useful idea: “what is one row of my answer?” Decide that first, and everything follows.
GROUP BY hotel.WHERE vs HAVING — the distinction the exam loves. WHERE runs before grouping and cannot see SUM/COUNT. HAVING runs after grouping and exists precisely to filter on them. “customers who spent more than 5000 in total” is a HAVING; “orders after 2024-01-01” is a WHERE.
Joining: put the tables in a chain along the foreign keys. To get from Guest to Hotel in the hotel database you must pass through Books and Room — you cannot jump, because no column links them directly.
Small tools: DISTINCT removes duplicate rows (“listed only once”). LIKE 'A%' = starts with A; LIKE '%burg' = ends with burg. COUNT(*) counts rows; SUM(a*b) multiplies then totals.
Write this — the exam answers
One output row represents one qualifying room. Path: ROOM → TYPE; filter TYPE.Price, then show ROOM.RoomID.
Checked result: 1, 3, 4, 5, 6, 8, 9, 10.
One row per room. “Between” is inclusive; classical RA has no order, so τ is an explicit extension.
Checked result: IDs 10, 9, 8, 6, 5, 4, 3, 1, with their type names. The supplied solution’s strict >20 AND <50 is corrected to inclusive BETWEEN.
One row per hotel name. Path: HOTEL → ROOM → TYPE; filter the type. π removes duplicates under relational set semantics; SQL needs DISTINCT.
Checked result: Beach Hotel.
One row per hotel—including a hotel with zero bookings. COUNT/outer join require extended RA. Count a non-null booking key, not the null-extended row.
Checked result: Grand Hotel 6; Beach Hotel 3; Bates Motel 3. The supplied inner joins are corrected because “all hotels” must preserve a zero-booking hotel.
One output row per guest name. The only connection is the four-relation path GUEST → BOOKING → ROOM → HOTEL.
Checked result: Susanne Brandt, Paul Brunel, Mika Aikonen, Illes Mihaly, Dominica Valderama.
First compute one BookingCost per booking; then group per guest, sum, and filter the groups. PostgreSQL date subtraction yields the number of charged nights used by the supplied solution.
Checked result: Rubie Kub €3,380; Paul Brunel €1,170; Mika Aikonen €1,600; Antonia Valetta €4,270; Illes Mihaly €1,040; Dominica Valderama €1,920.
Why each translation works
5.1.1 and 5.1.2 are filter–join–project. Price belongs to TYPE, while LivingArea belongs to ROOM. Push each σ/WHERE to the relation that owns the filtered attribute, join through TypeID, then project/select exactly the requested columns. Sorting is presentation and comes last.
5.2.1 exposes the set-versus-bag difference. Relational algebra relations are sets, so π produces each hotel name once. SQL keeps duplicate result rows unless DISTINCT is requested.
5.2.2 combines two separate requirements. “Per hotel” triggers γ/GROUP BY; “all hotels” triggers ⟕/LEFT JOIN. With an outer join, COUNT(*) would count the preserved null row as one, so count the nullable right-side booking key.
5.3.1 is a path-finding question. Guest and Hotel have no direct common key. Every algebra bowtie and SQL JOIN corresponds to one FK→PK edge in the relational model; skipping BOOKING or ROOM creates a meaningless product.
5.3.2 has two grains. Before grouping, one row is one booking and the computed value is nights × nightly price. After γ/GROUP BY, one row is one guest and Spent is the sum. Because “more than €800” applies to that total, the algebra σ sits outside γ and SQL uses HAVING, not WHERE.
RA ↔ SQL: σ=WHERE, π=SELECT DISTINCT, ⋈=JOIN, ⟕=LEFT JOIN, γ=GROUP BY/aggregate, σ after γ=HAVING, τ=ORDER BY.
ORDER BY … DESC when the prompt says “descending”.DISTINCT after “only once in the result set”.AS when the prompt asks to “show the amount”.🔴 Exam-core The final-exam slide lists “knowledge questions” as its own area; the architecture homework and lab are entirely of this type.
A one-word answer rarely scores. Use the same four-beat structure every time, and keep it to three or four lines:
Write this — model answers
Why — how to handle a definition you did not revise
Fall back on the four beats. Even without the textbook phrasing, “it is a kind of X, it works by Y, it solves Z, for example W” reads as understanding. Markers reward the mechanism and the consequence more than the exact wording.
Prefer a course example over a generic one. Naming hm_room.ro_hotel shows you can apply the idea to the material you were taught; naming “a table in some database” does not.
If asked to compare, give the trade-off. Normalization vs redundancy, index read-speed vs write-cost, view convenience vs recomputation. A comparison question wants both directions, not a list of virtues.
Watch the language. The exam is English and you may bring a dictionary — use it for the prompt wording rather than guessing what a term means. A misread verb (“list” vs “count”) changes the whole answer.
Draw what the requirements permit and forbid—not merely a picture of nouns.
🔴 Exam-core Prof. Scholz explicitly named ERM as a focus on 22 July 2026; the final-exam slide, Homework 03, Learning Labs 03–05, and Wrap-Up Task 1 corroborate it.
An ER answer earns its value from four decisions: entity boundaries, identifiers, relationship meaning, and cardinalities. Attributes are the easy part.
A thing with its own identity and several occurrences: Hotel, Room, Guest. Underline or otherwise mark the key attribute.
A fact connecting occurrences: Hotel includes Room; Guest books Room. Dates belong to BOOKS because they describe that fact.
Ask in both directions: “one hotel includes how many rooms?” and “one room belongs to how many hotels?” Write both ends.
| Wording | Model move | Check |
|---|---|---|
| “each X has exactly one Y” | X participates in an N:1 relationship to Y; X side is mandatory. | Can an X exist with zero Y? No. |
| “zero or many” | Optional many participation. | Include 0 in the minimum if min/max notation is used. |
| “for each order/booking…” | Attribute of the relationship, or an associative entity when the occurrence needs identity. | Would the value change for a different pairing/event? |
| “types will grow” | VehicleType is data in an entity, not five hard-coded subtypes. | Adding a type requires INSERT, not schema change. |
| “either producer or retailer” | Specialization. Mark disjointness; mark total only when every supertype occurrence must be one subtype. | Can one company be both? Can it be neither? |
Exam answer
HOTEL 1:N ROOM; ROOM N:1 TYPE; GUEST M:N ROOM through BOOKS(start_date, end_date). HOTEL and GUEST each have a composite address. Keys: hotel_id, room_id, type_id, guest_id.
Why each move is there
room_id + guest_id + start_date in the margin.M:N event → bridge(FK₁, FK₂, event discriminator, event attributes); include the discriminator in the key when repeats are allowed.
Homework 03 adds start/end dates to WORKS_FOR, HEADS, and BOSSES. Each becomes a history relation in the relational model. A useful key is normally the participants plus start_date; add CHECK (end_date IS NULL OR end_date > start_date).
Learning Lab 03 says CARESE will offer more vehicle types without changing the ER model. Therefore VEHICLE_TYPE is an entity; VEHICLE–TYPE is M:N, and RESERVATION links Customer, VehicleType, and Location with pickup/return dates.
Exam answer
CUSTOMER 1:N CAR; CAR 1:N ACCIDENT (0 allowed on Accident side); POLICY M:N CAR; POLICY 1:N PREMIUM_PAYMENT. PAYMENT has period_start, period_end, due_date, received_date. Use IDs for all entities and VIN as a candidate key for CAR.
Breakdown
“Associated with” does not make Accident an attribute: accidents repeat and have their own facts. A payment is not a multivalued amount; it has dates and therefore deserves an entity. The prompt says customers own one or more cars, so Customer participation in OWNS is total.
A repeating fact with its own dates/amounts is an entity or relationship occurrence, never a comma-separated attribute.
The model is not finished until every relationship has a home, every table has a key, and the constraints express the prompt.
🔴 Exam-core Prof. Scholz explicitly named the Relational Model as a focus on 22 July 2026; Wrap-Up Tasks 2–4 and Learning Labs 05 and 08 use the mapping pipeline.
| ER structure | Relational mapping | Typical key |
|---|---|---|
| Strong entity | One table containing atomic attributes. | Entity identifier. |
| Composite attribute | Store its components, not the parent label. | Unchanged. |
| 1:N relationship | Move the 1-side key into the N-side table as FK. Put relationship attributes there if each N occurrence has at most one relationship occurrence. | N-side PK. |
| 1:1 relationship | Place FK on the mandatory side; add UNIQUE. Separate table if both optional or the relationship has a life of its own. | FK is UNIQUE. |
| M:N relationship | Create bridge with both FKs and relationship attributes. | Both FKs, plus any event discriminator needed for repeats. |
| Subtype | Supertype table plus subtype table whose PK is also FK to supertype. | Inherited supertype ID. |
| Recursive 1:N | Nullable self-FK on the child/subordinate row. | Entity PK; self-FK is not the key. |
Exam answer
HOTEL(hotel_id, name, street, house_no, zip_code, city) ROOM_TYPE(type_id, name, description, price) ROOM(room_id, hotel_id FK→HOTEL, type_id FK→ROOM_TYPE, living_area) GUEST(guest_id, name, street, house_no, zip_code, city) BOOKING(room_id FK→ROOM, guest_id FK→GUEST, start_date, end_date)Primary key of BOOKING = (room_id, guest_id, start_date).
Breakdown
INCLUDES and IS_OF are 1:N, so their foreign keys move into ROOM. BOOKS remains a table because it is M:N and has dates. ZIP codes and house numbers are character data: leading zeroes and letters such as “15b” are meaningful.
(bo_room, bo_guest) contradicts the prompt’s explicit requirement that one guest may book the same room at different dates. Adding bo_start_date distinguishes those occurrences. The refined supplied model also labels ZIP as integer although its own SQL correctly uses character data.1:N → FK on N; M:N → bridge; 1:1 → FK on mandatory side + UNIQUE; subtype PK is also FK.
Exam answer
CREATE TABLE hm_hotel ( ho_id integer PRIMARY KEY, ho_name varchar(255) NOT NULL, ho_street varchar(255) NOT NULL, ho_house_number varchar(50) NOT NULL, ho_zip_code varchar(50) NOT NULL, ho_city varchar(255) NOT NULL ); CREATE TABLE hm_type ( ty_id integer PRIMARY KEY, ty_name varchar(255) NOT NULL UNIQUE, ty_description varchar(255), ty_price numeric(10,2) NOT NULL CHECK (ty_price >= 0) ); CREATE TABLE hm_room ( ro_id integer PRIMARY KEY, ro_hotel integer NOT NULL REFERENCES hm_hotel(ho_id), ro_type integer NOT NULL REFERENCES hm_type(ty_id), ro_living_area numeric(10,2) NOT NULL CHECK (ro_living_area > 0) ); CREATE TABLE hm_guest ( gu_id integer PRIMARY KEY, gu_name varchar(255) NOT NULL, gu_street varchar(255) NOT NULL, gu_house_number varchar(50) NOT NULL, gu_zip_code varchar(50) NOT NULL, gu_city varchar(255) NOT NULL ); CREATE TABLE hm_booking ( bo_room integer REFERENCES hm_room(ro_id), bo_guest integer REFERENCES hm_guest(gu_id), bo_start_date date NOT NULL, bo_end_date date NOT NULL, PRIMARY KEY (bo_room, bo_guest, bo_start_date), CHECK (bo_end_date > bo_start_date) );
ro_hotel integer NOT NULL REFERENCES hm_hotel(ho_id). Read it left to right: column → type → required → referenced parent. This inline form is equivalent to a separate one-column FOREIGN KEY clause. The 50/255 varchar sizes are consistent conventions for this exercise, not PostgreSQL presets.INSERT INTO hm_hotel VALUES (1,'Grand Hotel','Am Hauptplatz','1','84567','Pleinting'), (2,'Beach Hotel','Strandvej','15b','1234','Copenhagen'), (3,'Bates Motel','Park Avenue','59','01624','Fairvale'); INSERT INTO hm_type VALUES (1,'Single Apartment','Nice apartment with bathroom and bed',130), (2,'King Size Apartment','Nice apartment with king size bed and bathroom',260), (3,'Mini Suite','Luxury apartment with king size bed, living room and bathroom',320), (4,'Presidential Suite','Luxury apartment with king size bed, living room, bathroom and sauna',610); INSERT INTO hm_room VALUES (1,1,1,28),(2,1,3,64),(3,1,1,32),(4,2,2,44),(5,2,1,31), (6,2,2,44),(7,2,4,110),(8,3,1,34),(9,3,1,32),(10,3,1,36); INSERT INTO hm_guest VALUES (1,'Susanne Brandt','Saskia-Geyer-Gasse','25','53672','Stuhr'), (2,'Lorin Lee','Daniel-Geiger-Weg','3','82827','Biberach'), (3,'Rubie Kub','Magdalena-Bühler-Allee','1','70119','Esslingen'), (4,'Paul Brunel','Kieferweg','6','06145','Aschersleben'), (5,'Mika Aikonen','Förstergasse','3','88888','Hinterwinkl'), (6,'Antonia Valetta','Am Kai','12','28793','Radelshaven'), (7,'Illes Mihaly','Oswald-Römer-Strasse','85','48732','Alfhausen'), (8,'Renuga Sangalimuthu','Innerer Ring','119','10274','Berlin'), (9,'John Smith','Am Rande','15','87934','Bofenhausen'), (10,'Dominica Valderama','Falkenweg','9','58691','Mainburg'); INSERT INTO hm_booking VALUES (3,1,'2024-06-03','2024-06-05'),(9,2,'2024-06-04','2024-06-09'), (6,3,'2024-06-08','2024-06-21'),(2,1,'2024-06-09','2024-06-10'), (4,4,'2024-06-09','2024-06-12'),(2,5,'2024-06-10','2024-06-15'), (7,6,'2024-06-11','2024-06-18'),(3,7,'2024-06-11','2024-06-19'), (8,8,'2024-06-13','2024-06-17'),(1,4,'2024-06-14','2024-06-17'), (10,9,'2024-06-15','2024-06-20'),(2,10,'2024-06-15','2024-06-21');
Where the marks live
NOT NULL; prices/areas/date order use CHECK.numeric for money and text-like types for ZIP/house number.DDL audit: PK every table; FK target exists; mandatory→NOT NULL; domain→CHECK; exact money→numeric; identifiers such as ZIP/card/phone→text.
ALTER TABLE aircraft RENAME COLUMN range TO max_distance; ALTER TABLE flight ALTER COLUMN status SET DEFAULT 'On Time'; ALTER TABLE airport ADD CHECK (airport_code ~ '^[A-Za-z]');
The regular expression tests the first character. The supplied range comparison >= 'aaa' AND <= 'ZZZ' is collation-dependent and reverses lexical case ranges in many collations.
ON DELETE CASCADE removes dependent facts; SET NULL preserves the row but removes the link; RESTRICT/NO ACTION prevents the delete while references remain.
Never choose an action from habit: state the business effect. Message history, for example, may need a soft-deleted user rather than cascading all messages.
Use functional dependencies to prove the design; do not normalize by aesthetic instinct.
🔴 Exam-core Prof. Scholz explicitly named Normalization as a focus on 22 July 2026; it recurs in Homework 06–07, Learning Lab 07, the Wrap-Up, and Additional Exercises.
A functional dependency X → Y means: whenever two valid rows agree on X, they must agree on Y. It is a statement about all valid states allowed by the semantics—not a coincidence in the sample rows.
Superkey: uniquely determines all attributes, possibly with extras.
Candidate key: minimal superkey.
Prime attribute: appears in at least one candidate key.
“Minimal” means no proper subset still determines the relation; it does not mean “fewest columns among all keys.”
Exam answer
R(A,B,C,D,E), F = { A→C, E→D, B→C }
Attributes absent from every RHS are A, B, E, so every key must contain ABE.
(ABE)+ = ABE → add C using A→C (or B→C) → add D using E→D = ABCDE.
Candidate key = {A,B,E}. R is not BCNF because A, B, and E are not superkeys although each determines a non-trivial attribute.
Minimality and normal forms
Remove A: BE cannot derive A. Remove B: AE cannot derive B. Remove E: AB cannot derive D or E. Therefore the superkey is minimal. It also violates 2NF because C depends on proper subsets A and B, and D depends on E.
ABE | +C | +D = ABCDE. Under it, write three one-line removal tests. This is faster and more markable than prose.Key by closure: start with attributes absent from RHS; expand; then prove minimality by removing each attribute once.
| Form | Condition | Violation smell |
|---|---|---|
| 1NF | Each cell contains one value from its domain; no repeating group in one cell. | aid = "1,5" or attractions = "Louvre, Eiffel Tower". |
| 2NF | 1NF, and no non-prime attribute depends on a proper subset of any candidate key. | With key (sid,aid), student name depends on sid alone. |
| 3NF | For every non-trivial X→A, X is a superkey or A is prime. | sid→class and class→leader causes leader to depend transitively on sid. |
| BCNF | For every non-trivial X→Y, X is a superkey. | Any determinant that is not a superkey. |
Exam answer
After splitting repeating groups, use SCHOOL(sid, name, class, leader, aid, activity, hours).
FDs: sid→name,class; class→leader; aid→activity; (sid,aid)→hours.
(sid,aid)+ = sid,aid,name,class,leader,activity,hours, so (sid,aid) is the candidate key.
STUDENT(sid, name, class FK→CLASS) CLASS(class, leader) ACTIVITY(aid, activity) PARTICIPATION(sid FK→STUDENT, aid FK→ACTIVITY, hours)Each resulting determinant is a key of its relation, so the decomposition is BCNF under the stated FDs.
Classroom working example · build every stage
The original final relations above remain the answer. This example exposes the intermediate 1NF, 2NF, and 3NF schemas.
Every determinant shown is a key of its own relation.
Dependency-to-table reasoning
Normalize by determinant: student facts→STUDENT, activity facts→ACTIVITY, class facts→CLASS, pair facts→bridge(sid,aid,…).
ec_order to 3NFExam answer
customer_id→customer attributes; order_id→date, payment_id, customer_id; payment_id→card_number,payment_amount; item_id→name,unit_price; (order_id,item_id)→quantity.
Candidate key of the original 1NF relation: (order_id, item_id).
ALTER TABLE ec_order RENAME TO ec_order_old; CREATE TABLE ec_customer ( customer_id integer PRIMARY KEY, gender varchar(6), firstname varchar(50), lastname varchar(50), street varchar(75), house_number varchar(5), zip_code char(5), city varchar(75) ); CREATE TABLE ec_order ( order_id integer PRIMARY KEY, order_date date, customer_id integer NOT NULL REFERENCES ec_customer(customer_id) ); CREATE TABLE ec_payment ( payment_id bigint PRIMARY KEY, card_number varchar(20), payment_amount numeric(10,2), order_id integer NOT NULL UNIQUE REFERENCES ec_order(order_id) ); CREATE TABLE ec_item ( item_id integer PRIMARY KEY, item_name varchar(100), unit_price numeric(10,2) ); CREATE TABLE ec_order_item ( order_id integer REFERENCES ec_order(order_id), item_id integer REFERENCES ec_item(item_id), quantity integer NOT NULL CHECK (quantity > 0), PRIMARY KEY (order_id,item_id) ); INSERT INTO ec_customer SELECT DISTINCT or_customer_id,or_gender,or_firstname,or_lastname, or_street,or_house_number,or_zip_code,or_city FROM ec_order_old; INSERT INTO ec_order SELECT DISTINCT or_order_id,or_date,or_customer_id FROM ec_order_old; INSERT INTO ec_payment SELECT DISTINCT or_payment_id,or_card_number,or_payment_amount,or_order_id FROM ec_order_old; INSERT INTO ec_item SELECT DISTINCT or_item_id,or_name,or_unit_price FROM ec_order_old; INSERT INTO ec_order_item SELECT or_order_id,or_item_id,or_quantity FROM ec_order_old; -- Verified source range is 8.56 … 988.01, so this loses no rows. ALTER TABLE ec_item ADD CONSTRAINT unit_price_bounds CHECK (unit_price BETWEEN 0 AND 10000); DROP TABLE ec_order_old;
Classroom working example · build every stage
The FDs, candidate key, final five-table DDL, and data-copy statements above remain the original answer. This example shows the intermediate normal-form schemas.
One row per (order_id, item_id); all cells are atomic.
Each non-trivial determinant is a candidate key in its own relation; PAYMENT has candidate keys payment_id and order_id under the one-payment-per-order rule.
Corrections and verification
or_city.order_id UNIQUE in Payment and omits duplicated payment_id from Order.Order-line FD: item_id→name,unit_price; (order_id,item_id)→quantity. Quantity belongs in ORDER_ITEM, not ITEM.
Exam answer
C and E never appear on a RHS, so every key contains CE. Closures show ACE, BCE, and CDE each determine all attributes; removing any attribute from each fails.
Candidate keys: ACE, BCE, CDE. Not BCNF: A→B has determinant A, which is not a superkey (and other violations can be shown similarly).
Caution
The supplied answer’s decomposition AB, BCD, AEF does not preserve every listed dependency (notably CD→A and CE→F) as local constraints. The task asks only for keys and the BCNF verdict. If a decomposition is explicitly requested, one verified lossless BCNF result is CEF, AB, ACD, CDE; it does not preserve BC→D and AE→F locally, illustrating the dependency-preservation trade-off.
Classroom status-ladder example
1NF is assumed. It is not in 2NF because CE→F makes non-prime F depend on a proper subset of every candidate key; therefore it is not in 3NF. It is not in BCNF because A→B has a determinant that is not a superkey. Highest normal form: 1NF.
BCNF proof of failure: exhibit one non-trivial X→Y with X⁺ ≠ all attributes; decompose only if asked, then check losslessness and dependency preservation separately.
Read an expression from the inside out; write one operator for each phrase in the question.
🔴 Exam-core Prof. Scholz explicitly named Relational Algebra as a focus on 22 July 2026; the final-exam slide, Homework 05, and Learning Lab 06 corroborate it.
| Operator | Meaning | Schema/result warning |
|---|---|---|
| σcondition(R) | Select rows. | Schema unchanged. |
| πattributes(R) | Project columns. | Relational algebra removes duplicates. |
| ρalias(R) | Rename relation/attributes. | Needed for self-joins and ambiguous names. |
| R ∪ S, R ∩ S, R − S | Set combine/compare. | R and S must be union-compatible: same arity and matching domains. |
| R × S | Every pair. | Usually an intermediate before selection; size |R|×|S|. |
| R ⋈θ S | Join matching pairs by explicit condition. | Safest when names overlap. |
| R ⋈ S | Natural join on all same-named attributes. | Convenient only when every same name is intended as a join key. |
name or semester, natural join uses all such equal-name columns. Rename first or use a theta join so the predicate is visible.Exam answers
Miriam Seifert; Irina Romanova; Ramesh Venkatesh; Michele Bartoli; Rune Tronne; Gal Geva; Randy Rust.
Anne Smith; Bettina Krause; Konstantin Pfeiffer.
Operations Research; Programming Languages.
Irina Romanova.
Ramesh Venkatesh.
| Student | Course |
|---|---|
| Rune Tronne | Operations Research |
| Michele Bartoli | Macroeconomics |
| Michele Bartoli | Industrial Economics |
| Yusuf Mahouni | Information Systems |
Where the reasoning sits
RA “both” → project same key then ∩; “none” → all keys − participating keys; join names only after set logic.
Exam answer
σName='Konstantin Pfeiffer'(Professor) → professor #004. Project Professor# → {004}. Join with TakesPlace on Professor# → lecture 002 WT2023 and lecture 003 WT2023.
| Weekday | Timeslot |
|---|---|
| Thursday | 10–12 |
| Wednesday | 14–16 |
The final projection removes all other columns; these two tuples remain.
Procedure
Start at leaves, write each intermediate schema as well as rows. A projection node can discard a future join key only if the join has already used it.
schema: … and then its rows. If a column needed by the parent disappeared, your projection is too early.Operation tree: evaluate bottom-up; record schema at every node; never project away a key needed above.
Professors:
πname(Professor) πname(σarea_of_expertise='Computer Science'(Professor)) → Jane Doe; Jaqueline Jaques πname(Professor ⋈Professor.room_number=Room.room_number σplaces=3(Room)) → Ansgar Fromme; Jaqueline JaquesStudents:
πname,course_of_study(σcourse_of_study='Mathematics' ∨ course_of_study='Computer Science'(Student)) πStudent.name(Student ⋈ Attends ⋈ σtitle='Database Engineering'(Lecture)) → Mirjam Sloet; Josefine Stracker; Maria Durad; Eoin Seo-Hyun; Daniyal Romulus; Brunhild Nelu; Botros Eilidh Use ρold(Examines) and ρnew(Examines); select old.grade=5 ∧ old.semester='WT2022' ∧ new.semester='WT2023' with equal student and lecture keys → Josefine Stracker.Definitions: natural join derives equality predicates from all shared attribute names; theta join uses an explicit predicate. Unary operators take one relation (σ, π, ρ); binary operators take two (∪, ∩, −, ×, joins).
Before writing SELECT, decide what one output row represents. Then build joins, filters, grouping, and presentation in logical order.
🔴 Exam-core Prof. Scholz explicitly named SQL as a focus on 22 July 2026; the final-exam slide, Homework 08, Learning Lab 09, the Wrap-Up, and Additional Exercises corroborate it.
| Prompt phrase | SQL move | Frequent failure |
|---|---|---|
| “each / per” | GROUP BY the requested row grain. | Grouping by too many columns fragments totals. |
| “only once / distinct” | SELECT DISTINCT. | Assuming joins cannot duplicate. |
| “total more than …” | SUM(...) and HAVING. | Putting aggregate in WHERE. |
| “all hotels, plus count” | Start at Hotel, use LEFT JOIN, count a non-null booking key. | Inner join silently drops zero-booking hotels. |
| “never” | Correlated NOT EXISTS. | NOT IN becomes UNKNOWN when subquery yields NULL. |
| “between 20 and 50” | BETWEEN 20 AND 50, inclusive. | Writing strict >/< without evidence. |
Exam answers
-- 5.1.1 rooms below €300 SELECT r.ro_id FROM hm_room r JOIN hm_type t ON t.ty_id=r.ro_type WHERE t.ty_price < 300 ORDER BY r.ro_id; -- → 1, 3, 4, 5, 6, 8, 9, 10 -- 5.1.2 area between 20 and 50, descending SELECT r.ro_id, t.ty_name FROM hm_room r JOIN hm_type t ON t.ty_id=r.ro_type WHERE r.ro_living_area BETWEEN 20 AND 50 ORDER BY r.ro_id DESC; -- → 10, 9, 8, 6, 5, 4, 3, 1 with their type names -- 5.2.1 hotels offering a King Size Apartment SELECT DISTINCT h.ho_name FROM hm_hotel h JOIN hm_room r ON r.ro_hotel=h.ho_id JOIN hm_type t ON t.ty_id=r.ro_type WHERE t.ty_name='King Size Apartment'; -- → Beach Hotel -- 5.2.2 all hotels and number of bookings SELECT h.ho_name, COUNT(b.bo_room) AS visits FROM hm_hotel h LEFT JOIN hm_room r ON r.ro_hotel=h.ho_id LEFT JOIN hm_booking b ON b.bo_room=r.ro_id GROUP BY h.ho_id,h.ho_name ORDER BY h.ho_id; -- → Grand Hotel 6; Beach Hotel 3; Bates Motel 3 -- 5.3.1 guests who ever booked Grand Hotel SELECT DISTINCT g.gu_name FROM hm_guest g JOIN hm_booking b ON b.bo_guest=g.gu_id JOIN hm_room r ON r.ro_id=b.bo_room JOIN hm_hotel h ON h.ho_id=r.ro_hotel WHERE h.ho_name='Grand Hotel'; -- → Susanne Brandt, Paul Brunel, Mika Aikonen, Illes Mihaly, Dominica Valderama -- 5.3.2 guests spending more than €800 SELECT g.gu_name, SUM((b.bo_end_date-b.bo_start_date)*t.ty_price) AS spent FROM hm_guest g JOIN hm_booking b ON b.bo_guest=g.gu_id JOIN hm_room r ON r.ro_id=b.bo_room JOIN hm_type t ON t.ty_id=r.ro_type GROUP BY g.gu_id,g.gu_name HAVING SUM((b.bo_end_date-b.bo_start_date)*t.ty_price) > 800 ORDER BY g.gu_name;
| Guest | Spend | By-hand check |
|---|---|---|
| Antonia Valetta | €4,270 | 7 nights × €610 |
| Dominica Valderama | €1,920 | 6 × €320 |
| Illes Mihaly | €1,040 | 8 × €130 |
| Mika Aikonen | €1,600 | 5 × €320 |
| Paul Brunel | €1,170 | 3 × €260 + 3 × €130 |
| Rubie Kub | €3,380 | 13 × €260 |
Corrections to supplied answers
>20 AND <50 happens to return the same data here but does not faithfully implement “between” at the endpoints.COUNT(b.bo_room) then returns 0 for the preserved row.All parents + count children → parent LEFT JOIN child, GROUP BY parent key, COUNT(child non-null key).
Exam answers
-- 4.1.1 all customer names SELECT firstname,lastname FROM ec_customer; -- 4.1.2 customers with any order total > €5,000 SELECT c.firstname,c.lastname FROM ec_customer c WHERE EXISTS ( SELECT 1 FROM ec_order o JOIN ec_order_item oi ON oi.order_id=o.order_id JOIN ec_item i ON i.item_id=oi.item_id WHERE o.customer_id=c.customer_id GROUP BY o.order_id HAVING SUM(oi.quantity*i.unit_price)>5000 ); -- → Khairiya al-Mustafa €5,282.34; Awni el-Huq €6,488.12; -- Analisa Hogeda €5,169.99 -- 4.1.3 count customers who never bought a name beginning A SELECT COUNT(*) FROM ec_customer c WHERE NOT EXISTS ( SELECT 1 FROM ec_order o JOIN ec_order_item oi ON oi.order_id=o.order_id JOIN ec_item i ON i.item_id=oi.item_id WHERE o.customer_id=c.customer_id AND i.item_name LIKE 'A%' ); -- → 204 -- 4.2.1 orders newest first SELECT * FROM ec_order ORDER BY order_date DESC; -- 4.2.2 revenue by gender SELECT c.gender,SUM(oi.quantity*i.unit_price) AS revenue FROM ec_customer c JOIN ec_order o USING(customer_id) JOIN ec_order_item oi USING(order_id) JOIN ec_item i USING(item_id) GROUP BY c.gender; -- → female €241,582.99; male €277,355.37 -- 4.3.1 revenue per item SELECT i.item_name,SUM(oi.quantity*i.unit_price) AS revenue FROM ec_item i JOIN ec_order_item oi USING(item_id) GROUP BY i.item_id,i.item_name; -- 4.3.2 items with total revenue below €12,000 SELECT i.item_name,SUM(oi.quantity*i.unit_price) AS revenue FROM ec_item i JOIN ec_order_item oi USING(item_id) GROUP BY i.item_id,i.item_name HAVING SUM(oi.quantity*i.unit_price)<12000; -- → 70 items -- 4.3.3 products ordered by customers in a city ending “burg” SELECT DISTINCT i.item_name FROM ec_customer c JOIN ec_order o USING(customer_id) JOIN ec_order_item oi USING(order_id) JOIN ec_item i USING(item_id) WHERE c.city LIKE '%burg'; -- → 28 distinct product names
Why these are robust
The “ever” query uses a correlated EXISTS whose inner grouping is one order. The “never” query is NULL-safe. Product queries group by the stable ID plus displayed name. The dataset outputs were calculated from all 1,280 rows, not copied from the solution PDF.
SQL order: FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT.
Exam answers
INSERT INTO aircraft(aircraft_code,model,range) VALUES('NEW','Airbus A400',10000); UPDATE flight SET actual_arrival=actual_arrival+INTERVAL '45 minutes', status='Delayed' WHERE flight_id=5; -- models with range > 5,000 SELECT model FROM aircraft WHERE range>5000; -- Airbus A330-200; Airbus A380; Boeing 777-200LR -- planned flights per model on 15 June SELECT a.model,COUNT(*) AS flights FROM flight f JOIN aircraft a USING(aircraft_code) WHERE f.scheduled_departure::date=DATE '2024-06-15' GROUP BY a.model; -- A318 6; A330-200 3; A380 1; B757-300 3; B777-200LR 2 -- distinct models scheduled to arrive in Munich on 15 June SELECT DISTINCT a.model FROM flight f JOIN aircraft a USING(aircraft_code) JOIN airport p ON p.airport_code=f.arrival_airport WHERE p.city='Munich' AND f.scheduled_arrival::date=DATE '2024-06-15'; -- Airbus A318; Boeing 757-300; Boeing 777-200LR -- distinct direct destinations from Madrid, sorted SELECT DISTINCT arrival.city FROM flight f JOIN airport origin ON origin.airport_code=f.departure_airport JOIN airport arrival ON arrival.airport_code=f.arrival_airport WHERE origin.city='Madrid' AND f.scheduled_departure::date=DATE '2024-06-15' ORDER BY arrival.city; -- Chennai; Jakarta; Munich; Reykjavik -- Munich → Reykjavik with exactly one feasible stop SELECT f1.scheduled_departure,f2.scheduled_arrival, f2.scheduled_arrival-f1.scheduled_departure AS duration, stop.city AS stopover FROM flight f1 JOIN airport origin ON origin.airport_code=f1.departure_airport JOIN flight f2 ON f2.departure_airport=f1.arrival_airport JOIN airport stop ON stop.airport_code=f1.arrival_airport JOIN airport destination ON destination.airport_code=f2.arrival_airport WHERE origin.city='Munich' AND destination.city='Reykjavik' AND f2.scheduled_departure>f1.scheduled_arrival AND f1.scheduled_departure::date=DATE '2024-06-15'; -- Helsinki: 04:30→13:20 (9:50), 04:30→18:25 (14:55), -- 11:45→18:25 (7:40), elapsed with time-zone offsets. -- cities touched by no Boeing departure/arrival that day SELECT p.city FROM airport p WHERE NOT EXISTS ( SELECT 1 FROM flight f JOIN aircraft a USING(aircraft_code) WHERE a.model LIKE 'Boeing%' AND ( (f.departure_airport=p.airport_code AND f.scheduled_departure::date=DATE '2024-06-15') OR (f.arrival_airport=p.airport_code AND f.scheduled_arrival::date=DATE '2024-06-15') ) ); -- → Madrid
Verified corrections
DISTINCT.NOT EXISTS matches the English directly.timestamptz subtraction compares absolute instants. A cast to date uses the session time zone; in this exercise the intended calendar date is the displayed schedule date.Routing self-join: f1.arrival=f2.departure AND f2.scheduled_departure>f1.scheduled_arrival; duration=f2.arrival−f1.departure.
Use definition → mechanism → consequence → tiny example. Avoid empty slogans such as “ACID makes data safe.”
🔴 Exam-core “Knowledge questions” is explicitly named on the final-exam slide; architecture, ACID, pages, buffering, and WAL dominate 02_Architecture.pdf and Homework 02.
A database is the organized persistent data plus its schema. A DBMS is the software that defines, queries, secures, coordinates, and recovers that data. PostgreSQL is a DBMS; one named database inside it is not.
External: user/application views. Conceptual: global logical schema. Internal: physical files, pages, indexes. Mappings provide logical and physical data independence.
Exam answer
Excel can store tables and evaluate formulas, but it does not satisfy core relational-DBMS requirements: it lacks a DBMS-managed relational catalog and declarative integrity, complete set-level data language, transparent logical/physical data independence, transaction isolation/recovery, and centrally enforced authorization. A spreadsheet cell grid is therefore not an RDBMS merely because rows and columns resemble a relation.
Evidence link to Codd’s themes
Use two or three concrete rules, not all thirteen: an active online catalog queried through the same language, comprehensive relational data sublanguage, integrity independence, and set-level insert/update/delete. Excel may imitate pieces, but enforcement remains in user conventions and files.
RDBMS ≠ grid: DBMS-managed catalog + declarative constraints + set language + transactions/recovery + data independence.
| Property | Precise meaning | Failure it prevents |
|---|---|---|
| Atomicity | A transaction’s effects occur entirely or not at all. | Debit succeeds but credit is missing. |
| Consistency | A committed transaction takes the database from one constraint-valid state to another, assuming correct transaction logic. | Committed FK/CHECK violation. |
| Isolation | Concurrent transactions observe behavior allowed by the chosen isolation level, approaching a serial execution at the strongest level. | Lost updates, dirty/non-repeatable/phantom reads as governed by level. |
| Durability | After commit is acknowledged, effects survive a crash through durable logging/storage. | A confirmed booking disappears after power loss. |
Storage and memory transfer data in blocks, so the DBMS groups tuples into fixed-size pages (8 KiB by default in PostgreSQL). A page carries a header, item pointers, tuple data, and free space. Page IDs make caching, replacement, and disk I/O manageable.
A slotted page lets item identifiers remain stable while variable-length tuples move within the page.
Row store: all attributes of a tuple together—good for OLTP reads/writes of whole rows. Column store: values of one attribute together—good for scans/aggregation and compression in OLAP. This is a workload trade-off, not “column is newer and better.”
Exam answer
A checkpoint flushes dirty data pages and writes a checkpoint record to WAL so crash recovery can begin from the corresponding redo point. PostgreSQL 18 starts a checkpoint when checkpoint_timeout expires or max_wal_size is about to be exceeded; current defaults are 5 minutes and 1 GB. A 1-second timeout would force dirty-page flushing far too often and, with full-page writes, increase WAL volume after every checkpoint, causing heavy I/O and latency.
Current primary-source confirmation
The explanation and defaults are from the official PostgreSQL 18 WAL Configuration documentation. The slides correctly motivate WAL-before-page and dirty-buffer flushing; this official page confirms the current defaults.
Checkpoint = flush dirty pages + checkpoint WAL record; too frequent ⇒ repeated I/O and more full-page WAL; PG18 default timeout 5 min.
Exam answer
8 million machines × at most 500 sensors = 4,000,000,000 sensor tables. One reading = 8-byte timestamp + 4×8-byte numeric = 40 bytes. At 100 Hz: 4,000 bytes/s per sensor.
Payload-only time = 32 TiB ÷ 4,000 B/s ≈ 278.7 years.
Page-cap cross-check: floor(8192/40)=204 payload readings/page; (2³²−1) pages × 204 ÷ 100 readings/s ≈ 277.6 years.
One table per sensor is not feasible in one PostgreSQL database: 4.0 billion relations exceeds the current 1,431,650,303 relations/database limit, before indexes and practical overhead. Use shared measurement tables keyed by machine_id and sensor_id, with partitioning. The payload-only lifetime is about 278 years; real tuple/page/index overhead makes the practical value lower.
Independent discrepancy record
The supplied solution’s “about 272 years due to the page limit” is not reproducible from the stated 40-byte payload and 8 KiB pages: those assumptions give 277.6 years. Actual PostgreSQL rows require tuple headers and line pointers, but incorporating those would reduce the result far more and requires layout assumptions not stated in the exercise.
Current hard limits are confirmed in the official PostgreSQL 18 limits table.
Capacity: rate = samples/s × bytes/sample; lifetime = limit/rate; state payload/overhead assumptions and compare schema object count to DB limits.
Redundancy/inconsistency, isolated formats, difficult ad-hoc access, integrity rules in application code, weak concurrency control, and fragile atomicity/recovery. A DBMS centralizes schema, query, constraint, transaction, security, and recovery services.
Reads first seek a page in the buffer pool; on a miss, the DBMS loads it and may evict a victim. A clean victim needs no write; a dirty victim must be written after its WAL is durable. Pinning prevents eviction while a page is in use.
OLTP: many short concurrent transactions, point reads/updates, current operational data. OLAP: fewer long scans/aggregations over large histories. Workload shapes indexes, layout, and normalization/denormalization choices.
The rules describe a relational system ideal: information as table values, guaranteed access by relation/key/column, systematic NULL handling, online catalog, relational language, view updating where possible, set-level writes, independence, integrity, and distribution independence.
🟠 Exam-practical Prof. Scholz said all semester topics remain relevant on 22 July 2026, but views, procedures, functions, and triggers were not among the five focus areas and do not appear in the two exam-preparation sets.
| Object | One-line distinction | PostgreSQL cue |
|---|---|---|
| View | Named stored query; ordinary view stores definition, not rows. | CREATE VIEW … AS SELECT … |
| Procedure | Invoked action; may support transaction control when called appropriately. | CALL p(...) |
| Function | Returns a value/set and can appear in expressions/queries. | SELECT f(...) |
| Trigger | Automatically invokes a trigger function before/after/instead of an event. | CREATE TRIGGER … |
⚪ Low priority Installation commands, pgAdmin/psql navigation, and tool-specific ER export occur only in setup-oriented labs, not the exam-preparation tasks.
🗑️ Slide noise Decorative title/review divider slides and stock imagery repeat structure but contribute no assessable method.
Prof. Scholz confirmed that a specific iLearn learning lab is comparable to a mock exam. The email did not name it; the integrated Wrap-Up lab is the strongest local match. One route, no calculator, no memory sheet.
🔴 Exam-core Instructor briefing, 22 July 2026: a specific iLearn learning lab is mock-equivalent; learning labs and homework define the focus.
WHERE is used for an aggregate threshold instead of HAVING.COUNT(*) on a LEFT JOIN reports one for the null-extended row.NOT IN is vulnerable to NULL, or the anti-join is scoped to the wrong customer.The last-page reference: recognize the output language, write the minimum complete answer, and run one decisive check.
🟠 Exam-practical Synthesizes the output types named on the final-exam slide and the failure modes repeated across Wrap-Up, Additional Exercises, homework, and labs.
| If the prompt says… | Put this on paper | Fast invariant |
|---|---|---|
| “Draw/model the requirements” | Entities with keys, relationships, attributes, and both cardinalities. | Read every relationship sentence from both ends. |
| “Transform into relations / DDL” | One relation line per table, underlined PK, labelled FKs; then constraints. | Every FK targets a declared PK or UNIQUE key. |
| “Find keys / normalize” | FDs, closure of each minimal key, highest normal-form test, decomposition. | Every fact appears once and the original facts can be reconstructed by joins. |
| “Express in relational algebra” | Inside-out expression; rename when names collide; final projection last. | All attributes needed by later joins survive until those joins. |
| “For each / total / more than” | SQL with explicit joins, GROUP BY at the requested grain, HAVING for group filters. | One output row represents exactly the thing requested after “each/per”. |
| “All, including none / never” | LEFT JOIN + COUNT(non-null child key), or correlated NOT EXISTS. | Mentally test a parent with zero matching child rows and a NULL in the subquery. |
| “Explain” | Definition → mechanism → consequence → tiny example. | Replace any slogan with the failure it prevents. |
| Term | Precise meaning | Plain reading / exam use |
|---|---|---|
| Entity | A distinguishable kind of object with its own occurrences and identifier. | A noun that deserves its own rectangle and later its own table. |
| Relationship | An association among entity occurrences; it may have attributes. | A verb-shaped fact such as Guest BOOKS Room; dates describe the booking. |
| Cardinality | The permitted minimum and maximum number of related occurrences. | The answer to “how many from each side?” Include zero when participation is optional. |
| Candidate key | A minimal set of attributes that functionally determines every attribute of a relation. | Its closure is everything, and removing any member breaks that property. |
| Primary key (PK) | The candidate key chosen to identify rows; its values are unique and non-null. | The row’s declared identity. |
| Foreign key (FK) | Attributes whose non-null values must match a referenced candidate key. | The stored link to a parent row; usually placed on the N side of 1:N. |
| Functional dependency X → Y | Any two legal rows equal on X must also be equal on Y. | X fixes Y. It is a rule over all valid states, not an accident in today’s data. |
| Determinant | The left-hand side X of a functional dependency X → Y. | The attributes that decide a fact’s value and therefore suggest that fact’s home table. |
| Prime attribute | An attribute belonging to at least one candidate key. | Needed for the formal 2NF/3NF tests; “prime” does not mean “primary-key only”. |
| 3NF | For each non-trivial X → A, X is a superkey or A is prime. | Permits the prime-attribute exception; BCNF does not. |
| Selection σ | A relational-algebra operator that keeps rows satisfying a predicate. | The WHERE-like row filter. |
| Projection π | A relational-algebra operator that keeps named attributes and removes duplicate tuples. | The SELECT-list-like column choice, but with set semantics. |
| Join | A combination of related tuples satisfying a predicate. | Pair rows on keys; never leave the predicate implicit when same-named non-keys exist. |
| NULL | A marker for missing or inapplicable information, not a value equal to anything. | Comparisons yield UNKNOWN; use IS NULL and distrust NOT IN with nullable results. |
| Row grain | The real-world fact represented by one output row. | Say “one row per hotel/customer/order”; it tells you the GROUP BY columns. |
| Transaction | A unit of work governed by atomicity, consistency, isolation, and durability. | The boundary within which writes commit together or roll back together. |
| WAL | Write-ahead logging: the recovery log record is durable before its changed data page. | Log first, page later; recovery can redo/undo after failure. |
| Checkpoint | A recovery marker accompanied by flushing dirty pages according to DBMS policy. | Shortens recovery’s starting distance; doing it constantly creates extra I/O. |
Complete compact answers for every supplied exercise set. Core exam archetypes above remain the primary study route; this atlas closes subparts and lets you drill by original numbering.
Answers
1 Install and connect. Install PostgreSQL with pgAdmin, start the server, connect in pgAdmin to host localhost, port 5432, maintenance DB postgres; in psql use psql -U postgres -d postgres. Verify with SELECT version(); and SELECT current_database(),current_user;.
2 Name/history. PostgreSQL descends from the POSTGRES project at UC Berkeley, itself a successor to Ingres; “SQL” was added to the name as SQL support became central. Final line: POSTGRES + SQL → PostgreSQL.
3 Capacity. 8,000,000×500 = 4,000,000,000 tables, exceeding the current relations/database limit. Per sensor: 100×(8+4×8)=4,000 B/s; 32 TiB/4,000 B/s = 278.731 payload-only years. Page-only cross-check = 277.643 years; use shared/partitioned measurements, not one table/sensor.
Checks
Connection queries prove both server and identity. The storage result excludes tuple headers, page headers, item pointers, indexes, and operational headroom; state that assumption. The 272-year supplied page answer is recorded as non-reproducible from the stated numbers.
Rate×time=capacity; always state payload and storage-overhead assumptions.
Answers
1. Use one paper sheet per relation; stable IDs link sheets rather than copying names.
2.1. USER(user_id,nickname,first_name,last_name,birthday); CHAT(chat_id,title,created_at,created_by); CHAT_MEMBER(chat_id,user_id); MESSAGE(message_id,chat_id,author_id,reply_to,text,created_at). Create 6 User rows, 3 Chat rows, 9 membership rows (4+2+2 with one local user reused as appropriate), and 20 Message rows (10+5+5). Access a conversation by selecting MESSAGE rows with chat_id and sorting created_at; index message(chat_id,created_at).
2.2. Birthday belongs once in USER; lookup by user_id/nickname. Index nickname if it is a frequent unique search key.
2.3. Delete MESSAGE WHERE author_id=:u; USER remains, so birthday remains. With replies, use ON DELETE SET NULL for reply_to or delete replies in safe order.
2.4. Global latest: order all messages by created_at DESC, message_id DESC, take first. Per chat: ROW_NUMBER() OVER(PARTITION BY chat_id ORDER BY created_at DESC,message_id DESC)=1, or PostgreSQL DISTINCT ON (chat_id).
2.5. Update one CHAT row. 2.6. Update one USER row; messages reference the ID. Copying the name on every message would require many edits and cause inconsistency.
3.1. Point lookup by PK is fast; scanning message text or counting by unindexed surname prefix is slower. Index known access paths, but no single set of indexes optimizes every read and write: indexes cost storage and update work.
3.2. Concurrent edits need a transaction and a conflict policy. Lock the row briefly (SELECT … FOR UPDATE) or use optimistic version checking; keep transactions short. Last-writer-wins is fast but may lose an update.
3.3. Working memory holds only a small changing set; a DB buffer/cache holds hot pages while persistent storage retains the complete set. 3.4. Compute AVG(age) by scanning birthdays; an index usually cannot remove all aggregation work. A maintained summary can be faster but must be updated correctly; computing age from birthday avoids a stale stored age.
Design lesson
Identifiers separate identity from mutable labels; membership and messages are repeating facts; indexing is workload-specific; concurrency needs a defined isolation/conflict rule; cached/derived aggregates trade write complexity for read speed.
Store mutable entity facts once; reference stable IDs; index the actual (filter,join,sort) access path.
Answers
1. Excel lacks DBMS-managed relational catalog, comprehensive relational data language, declarative integrity/data independence, and transaction/concurrency/recovery services; therefore it is not an RDBMS.
2. A database page is the fixed-size unit the DBMS moves between disk and buffer pool. PostgreSQL commonly uses 8 KiB pages containing a header, item pointers, tuples, and free space. Pages amortize I/O and support addressing, caching, replacement, and recovery.
3. A checkpoint flushes dirty pages and records a WAL recovery point. PostgreSQL 18 defaults: 5 min timeout and 1 GB max WAL trigger. One second means frequent dirty-page writes and extra full-page WAL, harming throughput/latency.
Check
Each answer gives definition, mechanism, and consequence. Official PostgreSQL 18 WAL documentation is linked in Chapter 6.
Page = I/O/cache unit; WAL precedes dirty page; checkpoint bounds redo but costs I/O.
Answers
-- 1 in psql \l+ -- databases and sizes \du -- roles -- 2.1–2.2 run as an administrative role CREATE ROLE lecture LOGIN CREATEDB PASSWORD 'choose-a-password'; CREATE DATABASE lecture OWNER lecture; -- reconnect to database lecture as lecture CREATE SCHEMA messenger AUTHORIZATION lecture; SET search_path TO messenger; -- 2.3–2.7 CREATE TABLE me_user( us_id bigint PRIMARY KEY,us_nickname varchar(50), us_lastname varchar(50),us_firstname varchar(50),us_birthday date); CREATE TABLE me_chat( ch_id bigint PRIMARY KEY,ch_title varchar(255), ch_created_at timestamp,ch_created_by bigint REFERENCES me_user); CREATE TABLE me_chatuser( cu_userid bigint REFERENCES me_user, cu_chatid bigint REFERENCES me_chat, PRIMARY KEY(cu_userid,cu_chatid)); CREATE TABLE me_message( ms_id bigint PRIMARY KEY, ms_chat bigint REFERENCES me_chat, ms_refer bigint REFERENCES me_message(ms_id), ms_text text,ms_created_at timestamp, ms_created_by bigint REFERENCES me_user); -- 3.2 after executing MessengerData.sql SELECT * FROM messenger.me_message; INSERT INTO messenger.me_message (ms_id,ms_chat,ms_refer,ms_text,ms_created_at,ms_created_by) SELECT 11,c.ch_id,NULL,'I will be back.',CURRENT_TIMESTAMP,u.us_id FROM messenger.me_chat c CROSS JOIN messenger.me_user u WHERE c.ch_title='Saturday Night Fever' AND u.us_nickname='terminator'; \copy messenger.me_message TO 'messages.csv' CSV HEADER
2.8 integrity checks. Personal/group chats: structurally yes (membership count is not constrained). Delete a user’s messages but retain birthday: yes, delete Message rows only. Delete User yet retain their name in messages: no under the supplied schema/FK; use soft deletion/anonymized User row or an explicit author-name snapshot. Replies: yes through nullable self-FK ms_refer.
3.1. Execute MessengerData.sql in database lecture; verify counts: 5 users, 3 chats, 9 memberships, 10 messages before the new insert.
Integrity lesson
The lab’s supplied schema cannot satisfy every checklist item simultaneously. A foreign key preserves the author row, while deleting the author would violate it; a soft-delete policy is the normalized solution when history must remain attributable.
SELECT COUNT(*) per table and test an FK violation inside a transaction that you roll back.Historical identity: keep/soft-delete parent, or deliberately snapshot display name; do not promise a behavior the FK schema forbids.
Answers
1. COMPANY(company_id,name,legal_form) 1:N DEPARTMENT(department_id,name); EMPLOYEE(employee_id,name,birthday) works for exactly one Department; Department has one head Employee; EMPLOYEE has a recursive 1:N BOSSES relation (one boss to many subordinates). COMPANY has a disjoint, total specialization into PRODUCER(production_capacity) and RETAILER(storage_capacity), because “either … or …” excludes both/neither.
2. Replace current-valued links with temporal relationships: WORKS_FOR(employee,department,start_date,end_date), HEADS(employee,department,start_date,end_date), BOSSES(boss,subordinate,start_date,end_date). Suggested keys: (employee_id,start_date) for works/head history when an employee can hold one such role at an instant; (boss_id,subordinate_id,start_date) for boss history. Add end>start and business rules for non-overlap if required.
3. Monst-ER Park is an external interactive practice activity and has no written solution artifact. Completion requires playing the site; it is safe to skip in this three-day exam route after the paper drills.
Check
Task 2 changes cardinality over time: do not leave department_id/head_id/boss_id as single current fields if history is required. A company’s subtype attributes live only in subtype entities.
When a relationship changes over time, model its occurrences with start/end; key includes participants plus start.
Answers
1 Insurance. CUSTOMER(customer_id,name) 1:N CAR(vin,model); CAR 1:N ACCIDENT(accident_id,date,…), with zero accidents allowed; POLICY(policy_id,…) M:N CAR; POLICY 1:N PREMIUM_PAYMENT(payment_id,period_start,period_end,due_date,received_date,amount). “One or more” means total participation on Customer→Car, Policy→Car, and Policy→Payment sides.
2 CARESE. LOCATION(location_id,address) 1:N VEHICLE(vehicle_id,brand,seats); VEHICLE M:N VEHICLE_TYPE(type_id,name). CUSTOMER supertype (customer_id,name,address,phone) has disjoint subtypes PRIVATE(birthday,credit_card) and BUSINESS(vat,discount_category). RESERVATION is a ternary event linking Customer, VehicleType, and Location with pickup_date and return_date; add reservation_id or a composite event key. New types are rows.
3 Requirements. Record Lecture ID/title/description/type; semester offerings; professor assignments; rooms, weekdays, and timeslots; student attendance; exams, examiner/location; each student’s grade; prerequisites. Clarify whether two professors may co-teach, one room hosts overlapping lectures, repeated attempts, and tutor limits.
4 Lecture ER. PROFESSOR 1:N TEACHES LECTURE per Semester; LECTURE M:N STUDENT through ATTENDS(Semester); LECTURE N:M ROOM through TAKES_PLACE(Semester,Weekday,Timeslot); EXAM belongs to Lecture and has student attempts/examiner/grade; LECTURE has recursive M:N PREREQUISITE. Use offering (lecture,semester) as the anchor when semester-specific facts repeat.
Check
Requirements analysis names unresolved constraints rather than guessing. Ternary Reservation is justified because the same customer/type can be reserved at different locations and dates.
Growing classifications are entity rows; reservations/offerings are event entities when three dimensions and dates jointly identify the fact.
Answers
CREATE SCHEMA moviemanager; CREATE TABLE moviemanager.movie( movie_id bigint PRIMARY KEY,title varchar(200) NOT NULL, publication_date date); CREATE TABLE moviemanager.actor( actor_id bigint PRIMARY KEY,first_name varchar(80), last_name varchar(80),stage_name varchar(120),birthday date); CREATE TABLE moviemanager.library( library_id bigint PRIMARY KEY,name varchar(120) NOT NULL, address text); CREATE TABLE moviemanager.movie_actor( movie_id bigint REFERENCES moviemanager.movie, actor_id bigint REFERENCES moviemanager.actor, PRIMARY KEY(movie_id,actor_id)); CREATE TABLE moviemanager.library_movie( library_id bigint REFERENCES moviemanager.library, movie_id bigint REFERENCES moviemanager.movie, PRIMARY KEY(library_id,movie_id)); CREATE TABLE moviemanager.opening_hours( library_id bigint REFERENCES moviemanager.library, weekday smallint CHECK(weekday BETWEEN 1 AND 7), opens time,closes time,PRIMARY KEY(library_id,weekday), CHECK(closes>opens));
1.4 explanation. pgAdmin converts each M:N relation into a junction table because a foreign key on only one side can represent at most 1:N. 1.6. Generate SQL, inspect PK/FK targets and schema qualification, execute, then compare catalog tables to the model.
2. The supplied lecturemanager.sql implements Room, Professor, Student, Lecture, Attends, Teaches, Examines, TakesPlace, and Prerequisite with bridge keys. Import into schema lecturemanager; verify with \dt lecturemanager.* and catalog/ER view.
Check
Opening hours repeat by day, so one pair of open/close columns in Library is insufficient. A bridge has both foreign keys and a composite primary key to prevent duplicate pairs.
M:N in an ER tool becomes a junction table with both FKs and usually their composite PK.
Answers
1. Union = {007 James Bond, 008 Hans-Dieter Kurz, 013 Carla Chester, 014 Jodie Leer, 021 Anna Koivonnen, 023 Wladimir Ivanov, 042 Simon Jones, 123 Tawfik Hamed}. Intersection = {007 James Bond, 042 Simon Jones}. Table1−Table2 = {013 Carla Chester, 014 Jodie Leer, 123 Tawfik Hamed}. (The reverse difference would be {008 Hans-Dieter Kurz, 021 Anna Koivonnen, 023 Wladimir Ivanov}.)
2. character(n)/char(n)/bpchar(n): fixed-length and blank-padded. character varying(n)/varchar(n): variable length with limit. text: variable unlimited length. PostgreSQL’s lengthless bpchar is variable unlimited length with trailing spaces semantically insignificant; lengthless character means character(1). For general strings PostgreSQL recommends text or varchar; see the official PostgreSQL 18 character-type documentation.
3.
COMPANY(company_id,name,legal_form)PRODUCER(company_id PK/FK→COMPANY,production_capacity)RETAILER(company_id PK/FK→COMPANY,storage_capacity)DEPARTMENT(department_id,name,company_id FK→COMPANY)EMPLOYEE(employee_id,name,birthday)WORKS_FOR(employee_id FK, start_date,department_id FK,end_date)HEADS(department_id FK,start_date,employee_id FK,end_date)BOSSES(boss_id FK,subordinate_id FK,start_date,end_date)Checks
Set operators use whole tuples and remove duplicates. History keys include start date. Producer/Retailer inherit Company identity. The supplied relation listing names both recursive columns “EmployeeID”; distinct role names are required.
Set difference is directional; recursive relation columns need role names such as boss_id and subordinate_id.
Answers
1.1 Order database. CUSTOMER(customer_id,name); CATEGORY(category_id,name); PRODUCT(product_id,name,category_id FK); ORDERS(customer_id FK,product_id FK).
1.2 extension. Model CATEGORY 1:N recursive parent; PRODUCT 1:N VERSION; an ORDER event for customer/date/time and ORDER_LINE for version, quantity, and price. This permits the same customer/version at different times and simultaneous product versions.
1.3 refined model. CUSTOMER(customer_id,name); CATEGORY(category_id,name,parent_id FK→CATEGORY nullable); PRODUCT(product_id,name,category_id FK); VERSION(version_id,product_id FK,description); CUSTOMER_ORDER(order_id,customer_id FK,ordered_at); ORDER_LINE(order_id FK,version_id FK,quantity,unit_price). Check quantity>0 and unit_price≥0.
2.1 Lecture model. PROFESSOR(professor_id,name,expertise,room_id FK); ROOM(room_id,places); STUDENT(student_id,name,course_of_study); LECTURE(lecture_id,title,type,description); ATTENDS(lecture_id,student_id,semester); TEACHES(lecture_id,semester,professor_id); EXAMINES(lecture_id,student_id,semester,professor_id,grade,location); TAKES_PLACE(lecture_id,semester,room_id,weekday,timeslot); PREREQUISITE(lecture_id,prerequisite_id).
2.2 evaluation. Multiple courses/student: yes. Duplicate student names: yes (ID is key). One professor in a room: possible. Three professors in one room: possible (room FK is not UNIQUE). Same lecture in different semesters: yes because semester is in Attends key. Two professors teaching same lecture/semester: no under TEACHES PK(lecture,semester). A professor can sit in a room where another teaches: yes; no constraint links office occupancy to teaching.
3.1 tutors. TUTOR(student_id PK/FK→STUDENT); SUPPORTS(lecture_id,semester,student_id FK→TUTOR). PK(lecture_id,semester) enforces at most one tutor.
3.2 books. BOOK(book_id,title,publisher); AUTHOR(author_id,name); BOOK_AUTHOR(book_id,author_id); RECOMMENDED(lecture_id,book_id). 3.3 each M:N becomes the two-FK bridge just listed.
Check
A surrogate order_id separates the event from its customer/product pair. The TEACHES key and SUPPORTS key are business constraints, not only technical choices.
Choose bridge keys to encode the promised multiplicity: semester in repeated offerings; PK(lecture,semester) for at-most-one tutor.
Answers
Homework 05 1.1–1.2 and 2.1–2.2: expressions and result names are in Chapter 4 under “Homework 05.” Natural vs theta join and unary/binary definitions are stated there.
Learning Lab 06 1.1–1.6 and 2: all expressions, result rows, and the operation-tree trace are in Chapter 4.
Learning Lab 06 3.1 IMDB.
1 πname(Movies) 2 πfirst_name,last_name(σgender='F'(Actors)) 3 πd.first_name,d.last_name(σm.name='Aliens'(ρmMovies ⋈m.id=md.movie_id ρmdMovies_Directors ⋈md.director_id=d.id ρdDirectors)) 4 πd.first_name,d.last_name(ρdDirectors ⋈d.id=dg.director_id σgenre='Drama'∧prob≥0.5(ρdgDirectors_Genres)) 5 πm.name,m.year(σfirst_name='Arnold'∧last_name='Schwarzenegger'(Actors) ⋈ Roles ⋈ Movies ⋈ σgenre='Thriller'(Movies_Genres))3.2 reformulation. Push selections genre='Drama'∧prob≥0.5, actor name, and genre='Thriller' to their base relations before joins; project to required IDs/labels only after retaining join keys. This reduces intermediate tuples without changing set semantics.
Check
The chapter answers keep schemas compatible for intersection/difference and use renaming for repeated relations. IMDB result rows depend on the supplied ReLaX dataset/tool; the algebra above is the requested answer and was aligned with RelaX_Solution.txt.
Equivalent RA reformulation: push σ down; retain join keys; project late enough to preserve joins.
Answers
1.1–1.3. Full FDs, key, normal-form analysis, and BCNF decomposition are in Chapter 3. 1.4 SQL:
CREATE SCHEMA school; CREATE TABLE school.class( class_id varchar(3) PRIMARY KEY,leader varchar(100) NOT NULL); CREATE TABLE school.student( sid integer PRIMARY KEY,name varchar(100) NOT NULL, class_id varchar(3) NOT NULL REFERENCES school.class); CREATE TABLE school.activity( aid integer PRIMARY KEY,activity varchar(80) NOT NULL UNIQUE); CREATE TABLE school.participation( sid integer REFERENCES school.student, aid integer REFERENCES school.activity, hours integer NOT NULL CHECK(hours>=0), PRIMARY KEY(sid,aid));
2.1. Candidate key ABE. 2.2. Not BCNF because A→C, B→C, and E→D have determinants that are not superkeys. 2.3. A 2NF violation requires a non-prime attribute to depend on a proper subset of a candidate key. A one-attribute key has no non-empty proper subset, so such partial dependency cannot occur.
Check
The supplied SQL omits foreign keys from Student to Class and Participation to its parents; the corrected DDL includes them. Splitting “10b” into numeric level + class letter is optional unless the semantics require querying those parts.
2NF violation requires composite candidate key + non-prime attribute depending on a proper subset.
Answers
1.1. StudentID→Name,Gender; (StudentID,Unit)→Grade. Unit alone determines no other stored attribute. 1.2. Candidate key: (StudentID,Unit). 1.3. Original relation: 1NF yes; 2NF no because StudentID→Name,Gender is partial on (StudentID,Unit); therefore 3NF no and BCNF no. Final BCNF relations: STUDENT(StudentID,Name,Gender) and STUDENT_UNIT(StudentID,Unit,Grade), with StudentID as FK→STUDENT. Check grade 0–100 and gender in ('M','F','X').
2.1 CIA. Before 1NF: City→Country,CityPopulation,CountryPopulation,Capital,Attractions-list and Country→CountryPopulation. After 1NF: City→Country,CityPopulation,CountryPopulation,Capital and Country→CountryPopulation; City does not determine Attraction. 2.2. Candidate key before 1NF: City; after 1NF: (City,Attraction). Country is not a candidate key because Country+={Country,CountryPopulation}. 2.3. Original relation: 1NF no because Attractions contains a list; therefore 2NF, 3NF, and BCNF no. Final BCNF relations: COUNTRY(Country,CountryPopulation), CITY(City,Country FK→COUNTRY,CityPopulation,Capital), and CITY_ATTRACTION(City,Attraction), with City as FK→CITY.
3.1. Candidate keys ACE, BCE, CDE (closure-verified). 3.2. Not BCNF; A→B alone is a counterexample because A is not a superkey. No decomposition is requested; the supplied three-table decomposition does not preserve every listed dependency locally.
Checks
Exactly one capital per country is a cross-row business rule: a partial unique index on country where capital is true enforces at most one; “at least one” needs a deferred assertion/trigger or transaction workflow. It is not solved merely by normalization.
After removing a repeating group, recompute the candidate key; the repeated value often joins the old key.
Answers
1.1. FDs: IID→CID,Items,Date,Amount and CID→Name,City; key IID. Assuming Name is one atomic display value, the table is 1NF and 2NF (single-column key), but not 3NF/BCNF because CID is not a superkey. Decompose CUSTOMER(CID,Name,City) and INVOICE(IID,CID FK,Items,Date,Amount); both BCNF. Splitting first/last name is a separate domain/design choice, not required by 1NF.
Classroom working example · stage labels
1NF: INVOICE_1NF(IID,CID,Name,City,Items,Date,Amount). 2NF: unchanged because IID is a one-column key. 3NF: split IID→CID→Name,City into CUSTOMER and INVOICE. BCNF: unchanged because IID and CID are keys of their own relations.
1.2. A PostgreSQL schema is a namespace inside the currently connected database. Therefore connect to lecture first, create invoiceschema, and schema-qualify both table names:
-- current database: lecture CREATE SCHEMA invoiceschema; CREATE TABLE invoiceschema.customer( cu_id integer PRIMARY KEY, cu_firstname varchar(255) NOT NULL, cu_lastname varchar(255) NOT NULL, cu_city varchar(255) NOT NULL); CREATE TABLE invoiceschema.invoice( in_id integer PRIMARY KEY, in_customer integer NOT NULL REFERENCES invoiceschema.customer(cu_id), in_items integer NOT NULL CHECK(in_items>0), in_date date NOT NULL, in_amount numeric(10,2) NOT NULL CHECK(in_amount>=0));
The qualified form needs no search-path assumption. If Name stayed atomic in Task 1.1, use one cu_name column instead of first and last name.
1.3. ER: CUSTOMER 1:N INVOICE; keys CID/IID; invoice attributes Items, Date, Amount. Exporting with pgAdmin is a tool action; the model is the assessable output.
2.1 true/false. More than 1,000 aircraft impossible: false (char(3) has far more values). Each airport has exactly one city value: true per NOT NULL column, though several airports may share a city. Same departure/arrival airport forbidden: false, no such CHECK. Equal scheduled departure/arrival: true, impossible, because arrival>departure. Delayed flights selectable: true from scheduled vs actual/status. Aircraft cannot leave before it arrived: false; no cross-flight constraint.
2.2.
ALTER TABLE aircraft RENAME COLUMN range TO max_distance; ALTER TABLE flight ALTER COLUMN status SET DEFAULT 'On Time'; ALTER TABLE airport ADD CHECK(airport_code ~ '^[A-Za-z]');
Check
The supplied Task 1.2 answer omits the requested CREATE SCHEMA; adding it and qualifying the tables is the complete answer. A column being mandatory proves one city value per airport row, not a real-world uniqueness claim. Cross-row chronology between flights requires a much richer schedule constraint.
Schema truth comes only from declared constraints; plausible real-world rules are not enforced unless encoded.
Answers
1. Use the Lecture relations in Learning Lab 05 above; the supplied LearningLab08.sql creates all nine tables with PK/FK constraints in schema lectureschema. The composite keys make semester-specific attendance/teaching/exam/placement facts unique and BCNF under the intended determinants.
-- 2.1 split name safely (populate before dropping old) ALTER TABLE lm_student ADD COLUMN st_firstname varchar(50); ALTER TABLE lm_student ADD COLUMN st_lastname varchar(50); -- UPDATE with a reviewed parsing rule; names are not reliably split by first space. ALTER TABLE lm_student DROP COLUMN st_name; -- 2.2–2.3 ALTER TABLE lm_lecture ADD UNIQUE(le_title); ALTER TABLE lm_examines ALTER COLUMN ex_grade SET NOT NULL; -- 2.4 remove references, then room ALTER TABLE lm_professor DROP COLUMN pr_room; ALTER TABLE lm_takes_place DROP COLUMN tp_room; DROP TABLE lm_room; -- 2.5 CREATE TABLE lm_assistant( assistantnumber integer PRIMARY KEY, firstname varchar(50),lastname varchar(50), professor integer NOT NULL REFERENCES lm_professor(pr_number));
3 shopping tables.
CREATE TABLE customer(customer_id integer PRIMARY KEY,company varchar(120)); CREATE TABLE article(article_id integer PRIMARY KEY,name varchar(120)); CREATE TABLE purchase( customer_id integer REFERENCES customer, article_id integer REFERENCES article, bought_at timestamp,quantity integer CHECK(quantity>0), unit_price numeric(10,2) CHECK(unit_price>=0), PRIMARY KEY(customer_id,article_id,bought_at)); CREATE TABLE newsletter( newsletter_id integer PRIMARY KEY,topic varchar(120),publish_date date,name varchar(120)); CREATE TABLE subscription( customer_id integer REFERENCES customer, newsletter_id integer REFERENCES newsletter, PRIMARY KEY(customer_id,newsletter_id));
Check
Adding NOT NULL fails if current grades contain NULL; inspect and repair first. DROP … CASCADE is shorter but hides what is removed, so explicit dependent-column removal is safer for an exam explanation. Name parsing needs a domain rule or manual review.
Safe migration: add new structure, populate, validate, constrain, then remove old structure.
Answers
1. The W3Schools quiz is an external ungraded practice activity and has no stable written result; it is safe to skip after source-aligned SQL drills. 2.1–2.2 and 3.1–3.2: all INSERT, UPDATE, six corrected SELECT statements, explanations, and verified result rows appear in Chapter 5 under “Homework 08.”
Corrections retained
Use scheduled dates for “planned,” DISTINCT for unique cities/models, return the requested duration, check layover order, and express “no Boeing event” with correlated NOT EXISTS. The supplied solution misses or mis-scopes each of these points.
Temporal query: match the prompt’s clock (scheduled/actual), event (departure/arrival), date, and ordering.
Answers
SET search_path TO sales; -- 1.1 Customers SELECT COUNT(*) FROM customer; SELECT territoryid,COUNT(*) FROM customer GROUP BY territoryid ORDER BY COUNT(*) DESC; SELECT * FROM customer WHERE territoryid IS DISTINCT FROM 1; SELECT customerid FROM customer GROUP BY customerid HAVING COUNT(DISTINCT territoryid)>1; -- no rows are possible if customerid is the table PK and one row has one territoryid -- 1.2 Territory SELECT * FROM salesterritory; SELECT name FROM salesterritory WHERE countryregioncode='US' ORDER BY name; -- 1.3 SalesOrderHeader SELECT onlineorderflag,COUNT(*) AS orders FROM salesorderheader GROUP BY onlineorderflag; SELECT orderdate::date AS day,COUNT(*) AS orders FROM salesorderheader GROUP BY orderdate::date HAVING COUNT(*)>100 ORDER BY day; -- inspect returned dates for month-/quarter-end or promotion patterns -- 1.4 SalesOrderDetail SELECT productid,COUNT(DISTINCT salesorderid) AS orders FROM salesorderdetail GROUP BY productid ORDER BY orders DESC; SELECT productid,SUM(orderqty) AS units FROM salesorderdetail GROUP BY productid ORDER BY units DESC; SELECT productid,SUM(orderqty*unitprice) AS revenue FROM salesorderdetail GROUP BY productid ORDER BY revenue DESC; SELECT SUM(orderqty*unitprice) AS total_revenue FROM salesorderdetail; -- 2.1 Customers SELECT DISTINCT h.customerid,t.name AS territory FROM salesorderheader h JOIN salesterritory t ON t.territoryid=h.territoryid WHERE h.orderdate::date=DATE '2012-05-01'; SELECT h.customerid,SUM(d.orderqty) AS units FROM salesorderheader h JOIN salesorderdetail d USING(salesorderid) WHERE d.productid=729 GROUP BY h.customerid; SELECT DISTINCT h.customerid FROM salesorderheader h JOIN salesterritory t ON t.territoryid=h.territoryid WHERE h.orderdate>=DATE '2011-10-01' AND h.orderdate<DATE '2012-01-01' AND t.countryregioncode='DE'; SELECT h.customerid,SUM(d.orderqty*d.unitprice) AS revenue FROM salesorderheader h JOIN salesorderdetail d USING(salesorderid) GROUP BY h.customerid ORDER BY revenue DESC LIMIT 10; -- 2.2 Product SELECT d.productid,SUM(d.orderqty*d.unitprice) AS revenue FROM salesorderheader h JOIN salesorderdetail d USING(salesorderid) WHERE h.orderdate>=DATE '2011-08-01' AND h.orderdate<DATE '2011-09-01' GROUP BY d.productid ORDER BY revenue DESC; -- 2.3 Sales: corrected territory join SELECT t.name AS territory,r.name AS salesreason, SUM(d.orderqty*d.unitprice) AS revenue FROM salesterritory t JOIN salesorderheader h ON h.territoryid=t.territoryid JOIN salesorderdetail d USING(salesorderid) JOIN salesorderheadersalesreason hr USING(salesorderid) JOIN salesreason r USING(salesreasonid) GROUP BY t.territoryid,t.name,r.salesreasonid,r.name ORDER BY t.name,r.name;
Corrections and checks
IS DISTINCT FROM 1 includes customers whose territory is NULL; !=1 does not.>= start AND < next period) so timestamps on the last day are included.soh.territoryid=soh.territoryid is always true and creates a Cartesian multiplication. The correct join is Header.territoryid = Territory.territoryid.Join audit: every JOIN needs a predicate connecting left to right; reject self-equalities such as h.territoryid=h.territoryid.
Answer map
1 ER: Chapter 1 visual and answer. 2 relational model + normalization: Drill Lab 2 maps the model, states all semantic FDs and keys, and proves every corrected relation BCNF; Chapter 2 gives the relation lines. 3 DDL: Chapter 2 complete five-table SQL. 4 population: Chapter 2 all 3 hotels, 4 types, 10 rooms, 10 guests, and 12 bookings. 5.1–5.3: Drill Lab 5 pairs relational algebra with SQL for every subpart and checks the results; Chapter 5 repeats the final SQL set.
Discrepancies handled
Booking PK includes start date; ZIP is character; BETWEEN is inclusive; all-hotels count uses LEFT JOIN. These changes are explicitly documented at the point of use.
Integrated order: ER → relations → constraints → normalized inserts → queries → output checks.
Answer map
1 import: execute OrderDatabase.sql into lecture; it creates schema ecommerce and ec_order. 2.1–2.3: Chapter 3 gives corrected FDs, key, five 3NF tables, all copy statements, and source drop order. 3: Chapter 3 verifies existing unit prices 8.56–988.01, then adds a BETWEEN 0 AND 10000 CHECK without dropping data. 4.1–4.3: Chapter 5 gives all eight query answers plus verified facts from 1,280 rows.
Discrepancies handled
Quantity depends on (order,item), customer load includes city, and “never A” uses NOT EXISTS rather than NULL-sensitive NOT IN.
Wide-table normalization: mark determinants above columns, draw one table per determinant, keep pair-specific facts in the bridge.
This appendix explains what supports the priorities and where uncertainty remains.
Highest: Prof. Scholz’s 22 July briefing, the official exam plan, and the final-exam slide. Focus evidence: learning labs and homework, with the Wrap-Up as the strongest local match for the unnamed mock-equivalent iLearn lab. Scope: all semester material remains relevant. No past exams were present, so this book never claims “N of M past exams.”
Every page of every supplied PDF was rendered and visually reviewed. Numerical closures, storage calculations, hotel totals, airline results, and the full order dataset were independently recomputed. Supplied solutions were treated as fallible evidence.
The table maps every supplied course artifact to its learner-facing use. “Supplied solution, checked” means it informed the answer but was not trusted without comparison.
| Source | Pages | Role | Used in |
|---|---|---|---|
| 1-Introduction/01_Introduction.pdf | 40 | lecture/scope source | Ch. 6 capacity/DBMS; Atlas §1 |
| 1-Introduction/HomeWork01_en.pdf | 1 | exercise/data source | Ch. 6 capacity/DBMS; Atlas §1 |
| 1-Introduction/LearningLab01_en.pdf | 3 | exercise/data source | Ch. 6 capacity/DBMS; Atlas §1 |
| 1-Introduction/New-Features-of-PostgreSQL-18.txt | — | lecture/scope source | Ch. 6 capacity/DBMS; Atlas §1 |
| 1-Introduction/SolutionHomeWork01.pdf | 2 | supplied solution, checked | Ch. 6 capacity/DBMS; Atlas §1 |
| 2-Architecture-of-RDBMS/02_Architecture.pdf | 57 | lecture/scope source | Ch. 6 architecture/WAL; Atlas §2 |
| 2-Architecture-of-RDBMS/Homework_Architecture-of-RDBMS/HomeWork02_en.pdf | 1 | exercise/data source | Ch. 6 architecture/WAL; Atlas §2 |
| 2-Architecture-of-RDBMS/Learning-Lab_PostgreSQL-Basics/CreateMessengerTables.sql | — | exercise/data source | Ch. 6 architecture/WAL; Atlas §2 |
| 2-Architecture-of-RDBMS/Learning-Lab_PostgreSQL-Basics/LearningLab02_en_.pdf | 3 | exercise/data source | Ch. 6 architecture/WAL; Atlas §2 |
| 2-Architecture-of-RDBMS/Learning-Lab_PostgreSQL-Basics/MessengerData.sql | — | exercise/data source | Ch. 6 architecture/WAL; Atlas §2 |
| 3-Relational-Design/03_Design.pdf | 60 | lecture/scope source | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Homework_ER-model/HomeWork03.pdf | 1 | exercise/data source | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Homework_ER-model/SolutionHomeWork03.pdf | 2 | supplied solution, checked | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Learning-Lab_ER-Model/LearningLab03.pdf | 2 | exercise/data source | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Learning-Lab_ER-Model/SolutionLearningLab03.pdf | 3 | supplied solution, checked | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Learning-Lab_ER-Modelling-with-PostgreSQL/LearningLab04.pdf | 2 | exercise/data source | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Learning-Lab_ER-Modelling-with-PostgreSQL/lecturemanager.pgerd | — | exercise/data source | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Learning-Lab_ER-Modelling-with-PostgreSQL/lecturemanager.sql | — | exercise/data source | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Learning-Lab_ER-Modelling-with-PostgreSQL/moviemanager_extended.pgerd | — | exercise/data source | Ch. 1 ER; Atlas §3 |
| 3-Relational-Design/Learning-Lab_ER-Modelling-with-PostgreSQL/moviemanger_extended.sql | — | exercise/data source | Ch. 1 ER; Atlas §3 |
| 4-Relational-Model/04_RelationalModel.pdf | 68 | lecture/scope source | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Homework_Relational-Algebra/HomeWork05_en.pdf | 1 | exercise/data source | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Homework_Relational-Algebra/RelaX_HomeWork05.txt | — | exercise/data source | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Homework_Relational-Algebra/RelaX_Lecture.txt | — | exercise/data source | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Homework_Relational-Model/HomeWork04_en.pdf | 2 | exercise/data source | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Homework_Relational-Model/SolutionHomeWork04.pdf | 3 | supplied solution, checked | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Learning-Lab_Relational-Algebra/LearningLab06.pdf | 6 | exercise/data source | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Learning-Lab_Relational-Algebra/RelaX_IMDB_sample.txt | — | exercise/data source | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Learning-Lab_Relational-Algebra/RelaX_Solution.txt | — | supplied solution, checked | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Learning-Lab_Relational-Algebra/SolutionLearningLab06.pdf | 7 | supplied solution, checked | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Learning-Lab_Relational-Model/LearningLab05.pdf | 2 | exercise/data source | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/Learning-Lab_Relational-Model/SolutionLearningLab05.pdf | 6 | supplied solution, checked | Ch. 2/4 mappings & RA; Atlas §4 |
| 4-Relational-Model/ReLaX.txt | — | lecture/scope source | Ch. 2/4 mappings & RA; Atlas §4 |
| 5-Data-Definition-Language_SQL/05_DataDefinition.pdf | 58 | lecture/scope source | Ch. 2/3 DDL & normalization; Atlas §5 |
| 5-Data-Definition-Language_SQL/Homework_Creating-Tables/HomeWork07_en.pdf | 3 | exercise/data source | Ch. 2/3 DDL & normalization; Atlas §5 |
| 5-Data-Definition-Language_SQL/Homework_Creating-Tables/SolutionHomeWork07.pdf | 4 | supplied solution, checked | Ch. 2/3 DDL & normalization; Atlas §5 |
| 5-Data-Definition-Language_SQL/Homework_Normalization/HomeWork06_en.pdf | 2 | exercise/data source | Ch. 2/3 DDL & normalization; Atlas §5 |
| 5-Data-Definition-Language_SQL/Homework_Normalization/SolutionHomeWork06.pdf | 6 | supplied solution, checked | Ch. 2/3 DDL & normalization; Atlas §5 |
| 5-Data-Definition-Language_SQL/Learning-Lab_Creating-Relations/LearningLab08.sql | — | exercise/data source | Ch. 2/3 DDL & normalization; Atlas §5 |
| 5-Data-Definition-Language_SQL/Learning-Lab_Creating-Relations/LearningLab08_en.pdf | 2 | exercise/data source | Ch. 2/3 DDL & normalization; Atlas §5 |
| 5-Data-Definition-Language_SQL/Learning-Lab_Normalization/LearningLab07_en.pdf | 3 | exercise/data source | Ch. 2/3 DDL & normalization; Atlas §5 |
| 5-Data-Definition-Language_SQL/Learning-Lab_Normalization/SolutionLearningLab07.pdf | 6 | supplied solution, checked | Ch. 2/3 DDL & normalization; Atlas §5 |
| 6-Data-Manipulation-and-Selection-Language_SQL/06_DataManipulation.pdf | 57 | lecture/scope source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/Homework_Data-Manipulation-and-Selection/CreatingAirlineTables.sql | — | exercise/data source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/Homework_Data-Manipulation-and-Selection/HomeWork08_en.pdf | 2 | exercise/data source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/Homework_Data-Manipulation-and-Selection/SolutionHomeWork08.pdf | 2 | supplied solution, checked | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/Learning-Lab_SQL-Queries/Adventureworks.zip | — | exercise/data source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/Learning-Lab_SQL-Queries/LearningLab09_en.pdf | 2 | exercise/data source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/Learning-Lab_SQL-Queries/SolutionLearningLab09.pdf | 4 | supplied solution, checked | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/SQL-Island.txt | — | lecture/scope source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/SQL-Scripts/CreateViewAndTrigger.sql | — | exercise/data source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/SQL-Scripts/DataDefinition_Sales.sql | — | exercise/data source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/SQL-Scripts/DataInsert_Sales.sql | — | exercise/data source | Ch. 5 SQL; Atlas §6 |
| 6-Data-Manipulation-and-Selection-Language_SQL/SQL-Scripts/DataManipulation_en.sql | — | exercise/data source | Ch. 5 SQL; Atlas §6 |
| 7-Exam-Preparation/Learning-Lab_Additional-Exercises/LearningLabAdditionalExercise_en.pdf | 2 | exercise/data source | Core worked examples and rehearsal |
| 7-Exam-Preparation/Learning-Lab_Additional-Exercises/OrderDatabase.sql | — | exercise/data source | Core worked examples and rehearsal |
| 7-Exam-Preparation/Learning-Lab_Additional-Exercises/SolutionLearningLabAdditionalExercise.pdf | 5 | supplied solution, checked | Core worked examples and rehearsal |
| 7-Exam-Preparation/Learning-Lab_Wrap-Up/LearningLabWrapUp.pdf | 3 | exercise/data source | Core worked examples and rehearsal |
| 7-Exam-Preparation/Learning-Lab_Wrap-Up/SolutionLearningLabWrapUp.pdf | 6 | supplied solution, checked | Core worked examples and rehearsal |
| Supplied location | Issue | Correct exam move |
|---|---|---|
| Wrap-Up booking DDL | PK(room,guest) forbids repeat dates. | Add start_date to PK. |
| Wrap-Up refined model | ZIP labelled integer. | Use character/varchar. |
| Wrap-Up hotel count | Inner join omits zero visits. | LEFT JOIN and COUNT(child key). |
| Additional FDs | item_id→quantity is false. | (order_id,item_id)→quantity. |
| Additional customer load | City omitted from 8-column INSERT. | Select or_city too. |
| Homework 07 Task 1.2 | Supplied answer omits CREATE SCHEMA and schema qualification. | Connect to lecture; create invoiceschema; create invoiceschema.customer and invoiceschema.invoice. |
| Homework 07 airport CHECK | Lexical range is not a reliable starts-with-letter test. | Regex ~ '^[A-Za-z]'. |
| Homework 08 routes | Actual times, omitted DISTINCT/duration, broken anti-join. | Use scheduled event semantics and NOT EXISTS. |
| Learning Lab 09 sales | Always-true territory self-join. | h.territoryid=t.territoryid. |