Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

60
Common Table Expressions in MariaDB 10.2 Sergei Petrunia Galina Shalygina

Transcript of Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

Page 1: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

Common Table Expressions in MariaDB 10.2

Sergei PetruniaGalina Shalygina

Page 2: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

2

● A standard SQL feature

● Two kinds of CTEs

•Recursive

•Non-recursive

● Supported by Oracle, MS SQL Server, PostgreSQL, SQLite, …

● MySQL world:

•MariaDB: 10.2 Beta (Sept, 27th)

•MySQL: MySQL-8.0.0-labs-optimizer tree

Common Table Expressions

Page 3: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

3

Plan

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Page 4: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

4

Plan

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Page 5: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

5

CTE SyntaxCTE name

CTE Body

CTE Usage

● Similar to DERIVED tables● “Query-local VIEWs”

with engineers as ( select * from employees where dept='Engineering')select * from engineers where ...

WITH

Page 6: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

6

select *from( select * from employees where dept='Engineering') as engineerswhere...

with engineers as ( select * from employees where dept='Engineering')select * from engineers where ...

CTEs are like derived tables

● Similar to DERIVED tables● “Query-local VIEWs”

Page 7: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

7

Use case #1: CTEs refer to CTEs

● More readable than nested FROM(SELECT …)

with engineers as ( select * from employees where dept in ('Development','Support')),eu_engineers as ( select * from engineers where country IN ('NL',...))select ...from eu_engineers;

Page 8: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

8

with engineers as ( select * from employees where dept in ('Development','Support')),select * from engineers E1 where not exists (select 1 from engineers E2 where E2.country=E1.country and E2.name <> E1.name);

Use case #2: Multiple use of CTE● Anti-self-join

Page 9: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

9

select * from sales_product_year CUR, sales_product_year PREV,where CUR.product=PREV.product and CUR.year=PREV.year + 1 and CUR.total_amt > PREV.total_amt

with sales_product_year as ( select product, year(ship_date) as year, sum(price) as total_amt from item_sales group by product, year)

Use case #2: example 2● Year-over-year comparisons

Page 10: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

10

select * from sales_product_year S1where total_amt > (select 0.1*sum(total_amt) from sales_product_year S2 where S2.year=S1.year)

with sales_product_year as ( select product, year(ship_date) as year, sum(price) as total_amt from item_sales group by product, year)

Use case #2: example 3● Compare individuals against their group

Page 11: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

11

● Non-recursive CTES are “Query-local VIEWs”

● One CTE can refer to another

•Better than nested FROM (SELECT …)

● Can refer to a CTE from multiple places

•Better than copy-pasting FROM(SELECT …)

● CTE adoption

•TPC-H (1999) - no CTEs

•TPC-DS (2011) - 38 of 100 queries use CTEs.

Conclusions so far

Page 12: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

12

Plan

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Page 13: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

13

Base algorithm: materialize in a temp.table

● Always works● Often not optimal

with engineers as ( select * from employees where dept='Engineering' or dept='Support')select ...from engineers, other_table, ...

Page 14: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

14

Optimization #1: CTE Mergingwith engineers as ( select * from employees where dept='Development')select ...from engineers E, support_cases SCwhere E.name=SC.assignee and SC.created='2016-09-30' and E.location='Amsterdam'

select ...from employees E, support_cases SCwhere E.dept='Development' and E.name=SC.assignee and SC.created='2016-09-30' and E.location=’Amsterdam’

● for each support case•lookup employee by name

Page 15: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

15

Optimization #1: CTE Merging (2)

● Requirement

•CTE is a JOIN : no GROUP BY, DISTINCT, etc

● Output

•CTE is merged into parent’s join

•Optimizer can pick the best query plan

● This is the same as ALGORITHM=MERGE for VIEWs

Page 16: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

16

with sales_per_year as ( select year(order.date) as year sum(order.amount) as sales from order group by year)select * from sales_per_year where year in ('2015','2016')

with sales_per_year as ( select year(order.date) as year sum(order.amount) as sales from order where year in ('2015','2016') group by year)select * from sales_per_year

Optimization #2: condition pushdown

Page 17: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

17

Optimization #2: condition pushdown (2)Summary

● Used when merging is not possible

•CTE has a GROUP BY

● Makes temp. table smaller

● Allows to filter out whole groups

● Besides CTEs, works for derived tables and VIEWs

● MariaDB 10.2, Galina’s GSOC 2016 project:

“Pushing conditions into non-mergeable views and derived tables in

MariaDB”

Page 18: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

18

with product_sales as ( select product_name, year(sale_date), count(*) as count from product_sales group by product, year)select *from product_sales P1, product_sales P2where P1.year = 2010 AND P2.year = 2011 AND ...

Optimization #3: CTE reuse

● Idea•Fill the CTE once•Then use multiple times

● Doesn’t work together with condition pushdown or merging

Page 19: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

19

CTE Optimizations summary

● Merge and condition pushdown are most important

•MariaDB supports them, like MS SQL.

● PostgreSQL’s approach is *weird*

•“CTEs are optimization barriers”

● MySQL’s labs tree: “try merging, otherwise reuse”

CTE Merge Condition pushdown CTE reuse

MariaDB 10.2 ✔ ✔ ✘

MS SQL Server ✔ ✔ ✘

PostgreSQL ✘ ✘ ✔

MySQL 8.0.0-labs-optimizer ✔ ✘ ✔*

Page 20: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

20

Recursive CTEs

Page 21: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

21

Plan

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Page 22: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

22

Recursive CTEs

● First attempt: Oracle’s CONNECT BY syntax (80’s)● Superseded by Recursive CTEs

•SQL:1999, implementations in 2007-2009

● SQL is poor at “recursive” data structures/algorithms

wheel

boltcapnut

tire valve

rimtirespokes- Trees - Graphs

Chicago

Nashville Atlanta

Orlando

Page 23: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

23

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Plan

Page 24: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

24

Recursive CTE syntax

Recursive part

Anchor partRecursive use of CTE

“recursive”

with recursive ancestors as ( select * from folks where name = 'Alex' union [all] select f.* from folks as f, ancestors AS a where f.id = a.father or f.id = a.mother)select * from ancestors;

Page 25: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

25

Sister AmyAlex

Mom Dad

Grandpa Bill

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL || 98 | Sister Amy | 20 | 30 |+------+--------------+--------+--------+

Recursive CTE computation

Page 26: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

26

with recursive ancestors as ( select * from folks where name = 'Alex' union select f.* from folks as f, ancestors AS a where f.id = a.father or f.id = a.mother)select * from ancestors;

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 |+------+--------------+--------+--------+

Computation Result table

Step #1:execution of the anchor part

Page 27: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

27

with recursive ancestors as ( select * from folks where name = 'Alex' union select f.* from folks as f, ancestors AS a where f.id = a.father or f.id = a.mother)select * from ancestors;

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 |+------+--------------+--------+--------+

Computation Result table

+------+--------------+--------+--------+| id | name | father | moher |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL || 98 | Sister Amy | 20 | 30 |+------+--------------+--------+--------+

Step #2:execution of the recursive part

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL || 98 | Sister Amy | 20 | 30 |+------+--------------+--------+--------+

Page 28: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

28

with recursive ancestors as ( select * from folks where name = 'Alex' union select f.* from folks as f, ancestors AS a where f.id = a.father or f.id = a.mother)select * from ancestors;

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL |+------+--------------+--------+--------+

Computation Result table

Step #2:execution of the recursive part

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL || 98 | Sister Amy | 20 | 30 |+------+--------------+--------+--------+

Page 29: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

29

with recursive ancestors as ( select * from folks where name = 'Alex' union select f.* from folks as f, ancestors AS a where f.id = a.father or f.id = a.mother)select * from ancestors;

Computation Result table

Step #3:execution of the recursive part

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL |+------+--------------+--------+--------+

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL || 98 | Sister Amy | 20 | 30 |+------+--------------+--------+--------+

Page 30: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

30

with recursive ancestors as ( select * from folks where name = 'Alex' union select f.* from folks as f, ancestors AS a where f.id = a.father or f.id = a.mother)select * from ancestors;

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL |+------+--------------+--------+--------+

Computation Result table

Step #3:execution of the recursive part

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL || 98 | Sister Amy | 20 | 30 |+------+--------------+--------+--------+

Page 31: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

31

with recursive ancestors as ( select * from folks where name = 'Alex' union select f.* from folks as f, ancestors AS a where f.id = a.father or f.id = a.mother)select * from ancestors;

Computation Result table

Step #4:execution of the recursive part

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL || 98 | Sister Amy | 20 | 30 |+------+--------------+--------+--------+

+------+--------------+--------+--------+| id | name | father | mother |+------+--------------+--------+--------+| 100 | Alex | 20 | 30 || 20 | Dad | 10 | NULL || 30 | Mom | NULL | NULL || 10 | Grandpa Bill | NULL | NULL |+------+--------------+--------+--------+

No results!

Page 32: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

32

Summary so far

1. Compute anchor_data

2. Compute recursive_part to

get the new data

3. if (new data is non-empty)

goto 2;

with recursive R as ( select anchor_data union [all] select recursive_part from R, …)select …

Page 33: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

33

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Plan

Page 34: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

34

Transitive closure

bus_routes+------------+------------+ | origin | dst | +------------+------------+| New York | Boston || Boston | New York || New York | Washington || Washington | Boston || Washington | Raleigh |+------------+------------+

New York

Boston Washington

Raleigh

Page 35: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

35

with recursive bus_dst as ( select origin as dst from bus_routes where origin='New York' union select bus_routes.dst from bus_routes, bus_dst where bus_dst.dst= bus_routes.origin)select * from bus_dst

● Start from New York

New York

Boston Washington

Raleigh

Transitive closure

Page 36: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

36

with recursive bus_dst as ( select origin as dst from bus_routes where origin='New York' union select bus_routes.dst from bus_routes, bus_dst where bus_dst.dst= bus_routes.origin)select * from bus_dst

● Step #1: add Boston and Washington

Transitive closure +------------+ | dst | +------------+| New York |+------------+

New York

Boston Washington

Raleigh

Page 37: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

37

with recursive bus_dst as ( select origin as dst from bus_routes where origin='New York' union select bus_routes.dst from bus_routes, bus_dst where bus_dst.dst= bus_routes.origin)select * from bus_dst

● Step #1: add Boston and Washington

New York

Boston Washington

Raleigh

Transitive closure +------------+ | dst | +------------+| New York || Boston || Washington |+------------+

Page 38: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

38

with recursive bus_dst as ( select origin as dst from bus_routes where origin='New York' union select bus_routes.dst from bus_routes, bus_dst where bus_dst.dst= bus_routes.origin)select * from bus_dst

● Step#2:•Add Raleigh•UNION excludes nodes that are already present.

New York

Boston Washington

Raleigh

Transitive closure +------------+ | dst | +------------+| New York || Boston || Washington || Raleigh |+------------+

Page 39: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

39

UNION and MySQL-8.0-labs● UNION is useful for “transitive closure” queries

● Supported in all databases

● MySQL 8.0.0-labs

ERROR 42000: This version of MySQL doesn't yet support

'UNION DISTINCT in recursive Common Table Expression (use

UNION ALL)'

•No idea why they have this limitation.

Page 40: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

40

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Plan

Page 41: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

41

Computing “Paths”

bus_routes+------------+------------+ | origin | dst | +------------+------------+| New York | Boston || Boston | New York || New York | Washington || Washington | Boston || Washington | Raleigh |+------------+------------+

New York

Boston Washington

Raleigh

● Want paths like “New York -> Washington -> Raleigh”

Page 42: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

42

with recursive paths (cur_path, cur_dest) as ( select origin, origin from bus_routes where origin='New York' union select concat(paths.cur_path, ',', bus_routes.dest), bus_routes.dest from paths, bus_routes where paths.cur_dest= bus_routes.origin and locate(bus_routes.dest, paths.cur_path)=0)select * from paths

New York

Boston Washington

Raleigh

Computing “Paths”

Page 43: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

43

New York

Boston Washington

Raleigh

select concat(paths.cur_path, ',', bus_routes.dest), bus_routes.dest from paths, bus_routes where paths.cur_dest= bus_routes.origin and locate(bus_routes.dest, paths.cur_path)=0

+-----------------------------+------------+| cur_path | cur_dest |+-----------------------------+------------+| New York | New York || New York,Boston | Boston || New York,Washington | Washington || New York,Washington,Boston | Boston || New York,Washington,Raleigh | Raleigh |+-----------------------------+------------+

Computing “Paths”

Page 44: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

44

Recursion stopping summary● Tree or Directed Acyclic Graph walking

•Execution is guaranteed to stop

● Computing transitive closure

•Use UNION

● Computing “Paths” over graph with loops

•Put condition into WHERE to stop loops/growth

● Safety measure: @@max_recursive_iterations

•Like in SQL Server

•MySQL-8.0: @@max_execution_time ?

Page 45: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

45

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Plan

Page 46: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

46

[Non-]linear recursion

with recursive R as ( select anchor_data

union [all]

select recursive_part from R, …)select …

The SQL standard requires that

recursion is linear:

● recursive_part must refer to R only

once

•No self-joins

•No subqueries

● Not from inner side of an outer join

● …

Page 47: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

47

Linearity of SELECT statements● Recursive CTE is a “function”: R(x)=a

R

● Linear “function”: R(x+y)=a+b

•added rows in source -> added rows in the result

x a

+y+b

Page 48: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

48

Linear recursion

with recursive R as ( select anchor_data

union [all]

select recursive_part from R, …)select …

A

Page 49: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

49

with recursive R as ( select anchor_data

union [all]

select recursive_part from R, …)select …

Linear recursion

● New data is generated by “wave-front” elements

● Contents of R are always growing

Page 50: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

50

Non-linear recursion● Next version of R is computed from the

entire R (not just “wavefront”)

● R may grow, shrink, or change

● It’s possible to screw things up

•R may flip-flop

•R may be non-deterministic

● Still, MariaDB supports it:

set @@standard_compliant_cte=0

•Be sure to know what you’re doing.

Page 51: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

51

● Non-recursive CTEs•Use cases•Optimizations

● Recursive CTEs•Basics•Transitive closure•Paths•(Non-)linear recursion•Mutual recursion

Plan

Page 52: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

52

● Multiple CTEs refer to each other

● Useful for “bipartite” graphs

•emp->dept->emp

● MariaDB supports it

● No other database does

with recursive C1 as ( select … from anchor_table union select … from C2), C2 as ( select … from C1)select ...

Mutual recursion

Page 53: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

53

Conclusions● MariaDB 10.2 has Common Table Expressions

● Both Recursive and Non-recursive are supported

● Non-recursive

•“Query-local VIEWs”

•Competitive set of query optimizations

● Recursive

•Useful for tree/graph-walking queries

•Mutual and non-linear recursion is supported.

Page 54: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

54

Rate My Session!

Page 55: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

55

● Bill of materials

Tree-walking

Which part of bicycle is nut situated in?

Page 56: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

56

+------+------------+-------+---------+| id | name | count | part_of |+------+------------+-------+---------+| 10 | nut | 1 | 7 |+------+------------+-------+---------+

Bill of materials

wheel

boltcapnut

tire valve

rimtirespokes

with recursive nut as ( select * from bicycle_parts where name = 'nut' union select b.* from bicycle_parts as b, nut AS n where b.id = n.part_of )select * from nutwhere part_of = NULL;

Page 57: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

57

+------+------------+-------+---------+| id | name | count | part_of |+------+------------+-------+---------+| 10 | nut | 1 | 7 || 7 | tire valve | 2 | 4 |+------+------------+-------+---------+

Bill of materials

wheel

boltcapnut

tire valve

rimtirespokes

with recursive nut as ( select * from bicycle_parts where name = 'nut' union select b.* from bicycle_parts as b, nut AS n where b.id = n.part_of )select * from nutwhere part_of = NULL;

Page 58: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

58

+------+------------+-------+---------+| id | name | count | part_of |+------+------------+-------+---------+| 10 | nut | 1 | 7 || 7 | tire valve | 2 | 4 || 4 | tire | 2 | 1 |+------+------------+-------+---------+

Bill of materials

wheel

boltcapnut

tire valve

rimtirespokes

with recursive nut as ( select * from bicycle_parts where name = 'nut' union select b.* from bicycle_parts as b, nut AS n where b.id = n.part_of )select * from nutwhere part_of = NULL;

Page 59: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

59

+------+------------+-------+---------+| id | name | count | part_of |+------+------------+-------+---------+| 10 | nut | 1 | 7 || 7 | tire valve | 2 | 4 || 4 | tire | 2 | 1 || 1 | wheel | 2 | NULL |+------+------------+-------+---------+

wheel

boltcapnut

tire valve

rimtirespokes

Bill of materials

with recursive nut as ( select * from bicycle_parts where name = 'nut' union select b.* from bicycle_parts as b, nut AS n where b.id = n.part_of )select * from nutwhere part_of = NULL;

Page 60: Common Table Expressions in MariaDB 10.2 (Percona Live Amsterdam 2016)

60

with recursive nut as ( select * from bicycle_parts where name = 'nut' union select b.* from bicycle_parts as b, nut AS n where b.id = n.part_of )select * from nutwhere part_of = NULL;

It is a part of wheel!

Bill of materials

+------+------------+-------+---------+| id | name | count | part_of |+------+------------+-------+---------+| 1 | wheel | 2 | NULL |+------+------------+-------+---------+