Study Vault Search notes, aliases and full text
Graph
LectureDBISAI-written · not yet proofread

VL05 Joins and more SQL

The join operation and its computation via hash join and merge join, outer/natural/non-equi joins, the formal group-by operation with HAVING, and ORDER BY, LIMIT/OFFSET and subqueries in SQL.

Held Source lecture-05

Organisation#

Join operation#

Motivation (Slide 5). A very frequent pattern in SQL queries: two tables T1,T2T_1, T_2 in the FROM clause and a condition T1.col1 = T2.col2 in the WHERE clause. The query from Lecture 4 contains it twice:

SELECT movies.title, persons.name
FROM movies, persons, roles
WHERE roles.person_id = persons.id
AND roles.movie_id = movies.id;

A table is a triple T=(D,C,R)T = (D, C, R) in the sense of the Relational Model: CC the tuple of column names, DD the tuple of domains, RR the multiset of rows.

See Join.

Why the name? (Slide 8)

  • Single-column: the equality constraint concerns only one column of each table. A multi-column join (same number of columns from each table) can be defined analogously.
  • Equi-join: the condition is equality of the values in column j1j_1 of T1T_1 and j2j_2 of T2T_2. Other conditions are possible.

Cartesian product vs. join (Slide 9). The query above can be evaluated by two query plans in the operations of Relational Algebra:

  1. T1=cartesian-product(profs,studis)T_1 = \text{cartesian-product}(\texttt{profs}, \texttt{studis}), then T2=select(T1,r↦r[2]=r[4])T_2 = \mathrm{select}(T_1, r \mapsto r[2] = r[4]).
  2. T1=join(profs,studis,2,2)T_1 = \mathrm{join}(\texttt{profs}, \texttt{studis}, 2, 2).

Both give the same table, but the second never materialises the Cartesian product.

Join processing#

Hash join#

Merge join#

lecture-05, PDF page 14
lecture-05, PDF page 14

Cost estimates for ES5#

These estimates extend the per-operation cost model of query plans from Lecture 4.

Particularities of SQLite3#

(Slide 17)

  • SQLite3 has no hash join. Its documentation (https://www.sqlite.org/optoverview.html) claims, dubiously, that “an automatic index is about the same thing as a hash join”.
  • SQLite3 does not perform a merge join either. It always iterates over the values of one join column and searches them in the other, using an index if one exists or building a temporary index otherwise (more in Lecture 6).
  • A typical RDBMS supports both merge and hash joins; choosing between them is part of query planning.

More join operations#

Inner and outer joins (Slide 18). The join defined above only includes rows whose join value occurs in both tables: an inner join (the default). Variants:

  • Left outer join: additionally include the rows of T1T_1 (“left”) whose join value does not occur in T2T_2; the missing columns are filled with NULL.
  • Right outer join: analogously for the rows of T2T_2.
  • (Full) outer join: both left and right.

These are not defined formally in the lecture, only by example.

The following three queries are equivalent:

SELECT * FROM profs, studis WHERE profs.course = studis.course;  -- traditional
SELECT * FROM profs JOIN studis ON profs.course = studis.course; -- most modern
SELECT * FROM profs NATURAL JOIN studis;                         -- join columns (too) implicit

Non-equi join (Slide 22). The join condition need not be equality. Example, a spatial join: all restaurants within 500 m of a bus stop.

CREATE TABLE bus_stops(name TEXT, loc POINT);
CREATE TABLE restaurants(name TEXT, loc POINT);
SELECT * FROM bus_stops JOIN restaurants
ON ST_Distance(bus_stops.loc, restaurants.loc) < 500;

The exact syntax depends on the database; SQLite3 needs the SpatiaLite extension.

Grouping#

Motivation (Slide 23). Many queries group the rows of a table by a common value and compute something per group, e.g. all movies by the same director and their average IMDb score (a variant is on ES5).

The slide uses jj for both the aggregate index and the “for all” quantifier; here ii is used for the latter. See Grouping.

HAVING (Slide 26). To keep only groups with max_score > 8.0, a WHERE condition does not work: max_score is not a column of the original table but is created by the GROUP BY. Conditions on the results of aggregate functions are written in the HAVING clause.

Implementation and cost estimates (Slide 28). The straightforward implementation uses a hash map from grouping values to groups (part of ES5, Exercise 1). For an input table with nn rows and an output table with kk columns:

cost∼n⋅k,rows∼n/2,cols=k.\text{cost} \sim n \cdot k, \qquad \text{rows} \sim n/2, \qquad \text{cols} = k.

Assumptions: the average group size is 2 (arbitrary and unrealistic); insertion into a hash map takes constant time (realistic); evaluating fjf_j takes time linear in the number of arguments (often realistic).

Limits of GROUP BY (Slide 29). “For each year, the movie with the highest score and its title” needs a GROUP BY but cannot be expressed with GROUP BY alone. The query above yields the maximum score per year, but GROUP BY aggregates per column, while here the title is needed from the row that has a property (highest score) in another column.

More SQL#

(Slide 30) The SQL standard (ISO/IEC 9075:2023) has hundreds of pages; the course covers only the most important operations (see https://sqlite.org/lang.html). The following three are explained by example only, without formal operations. All are needed frequently and on ES5. Their position in a query is summarised in SQL Query Structure.

ORDER BY#

(Slide 31) By the definition from Lecture 4, tables are multisets of rows and have no inherent order. An order for the final result is requested with ORDER BY <expression> [ASC|DESC] at the end of the SELECT query. With a GROUP BY, the ORDER BY comes after it.

SELECT * FROM movies ORDER BY score DESC;

SELECT year, MAX(score) AS max_score FROM movies
GROUP BY year ORDER BY year ASC;

LIMIT and OFFSET#

(Slide 32) Given an order, LIMIT restricts the result to a prefix of the sorted rows, and OFFSET skips rows to select a segment in the middle.

-- the 10 movies with the highest scores
SELECT title, score FROM movies
ORDER BY score DESC LIMIT 10;

-- the 5 movies after the top 10
SELECT title, score FROM movies
ORDER BY score DESC LIMIT 5 OFFSET 10;

Clause order: GROUP BY → ORDER BY → LIMIT / OFFSET.

Subqueries#

(Slide 33) All operations take tables as arguments and a SELECT query produces a table. Hence, wherever SQL expects a table, a whole SELECT query in parentheses can be written instead.

SELECT title FROM movies
JOIN directors ON movies.movie_id = directors.movie_id
JOIN (
  SELECT DISTINCT person_id FROM awards
  WHERE award_name LIKE 'Academy Awards%'
) AS awardees ON directors.person_id = awardees.person_id;

Explanation (Slide 34). The subquery yields a one-column table with the person IDs of all Oscar winners. Effectively the query runs on

CREATE TABLE movies(movie_id INT, title TEXT, ...);
CREATE TABLE directors(movie_id INT, person_id INT);
CREATE TABLE awardees(person_id INT);

and is equivalent to

SELECT title FROM movies
NATURAL JOIN directors NATURAL JOIN awardees;

i.e. the titles of all movies directed by Oscar winners.

References#

(Slide 35) Wikipedia: Relational algebra (other joins), Hash join, Sort-merge join, SQL. SQLite3: why there are no merge joins (https://www.sqlite.org/optoverview.html#hash_joins), SELECT syntax (https://sqlite.org/lang_select.html).

Concepts#

  • Join — single-column equi-join, its hash/merge join computation, and the inner/outer/natural/spatial variants
  • Grouping — formal group-by operation, HAVING, hash-map implementation and cost estimate
  • SQL Query Structure — JOIN … ON, GROUP BY/HAVING, ORDER BY, LIMIT/OFFSET and subqueries in a SELECT query
  • Relational Algebra — Cartesian product + select as the join-free alternative; project with distinct inside the group-by definition
  • Query Plan — cost/size estimates for join and group-by used to compare query plans on ES5
  • List Intersection — the Zipper algorithm underlying the merge join
  • Cartesian Product — all row combinations of two tables, the basis of the join-free formulation
  • Ordering — ORDER BY, with LIMIT and OFFSET selecting a segment of the sorted rows
  • Hash Join — join via a hash map over one table’s join column
  • Merge Join — join of sorted join columns via the Zipper algorithm
  • Outer Join — left/right/full join keeping unmatched rows with NULLs
  • Natural Join — equi-join on all equally named columns
  • Subquery — a SELECT query used in place of a table

Search

Type In
↑ ↓ move ↵ open ⇥ next section Ctrl↵ results page Prefix # to search text only