CTE in MySQL 8.0
Many database systems support Common Table Expression, which is a great feature from SQL. And the most interesting variant is the recusive CTE. As for MySQL 8.0, Percona have published a series of interesting articles on it1, 2.
Just as recursion in any other programming languages, it must have a termination condition. But there are other subtleties in SQL, the values of a data type have a limitation, too. Let’s see an example calculating factorials.
Without terminating condition in the recursive query.
mysql> WITH RECURSIVE factorial(n, f) AS (
-> SELECT 0, 1
-> UNION ALL
-> SELECT n + 1, f * (n + 1) FROM factorial
-> )
-> SELECT * FROM factorial;
ERROR 1690 (22003): BIGINT value is out of range in '(`factorial`.`f` * (`factorial`.`n` + 1))'
With terminating condition (n < 20).
mysql> WITH RECURSIVE factorial(n, f) AS (
-> SELECT 0, 1
-> UNION ALL
-> SELECT n + 1, f * (n + 1) FROM factorial WHERE n < 20
-> )
-> SELECT * FROM factorial;
+------+---------------------+
| n | f |
+------+---------------------+
| 0 | 1 |
| 1 | 1 |
| 2 | 2 |
| 3 | 6 |
| 4 | 24 |
| 5 | 120 |
| 6 | 720 |
| 7 | 5040 |
| 8 | 40320 |
| 9 | 362880 |
| 10 | 3628800 |
| 11 | 39916800 |
| 12 | 479001600 |
| 13 | 6227020800 |
| 14 | 87178291200 |
| 15 | 1307674368000 |
| 16 | 20922789888000 |
| 17 | 355687428096000 |
| 18 | 6402373705728000 |
| 19 | 121645100408832000 |
| 20 | 2432902008176640000 |
+------+---------------------+
21 rows in set (0.01 sec)
Make n a little bit larger: n < 21.
mysql> WITH RECURSIVE factorial(n, f) AS (
-> SELECT 0, 1
-> UNION ALL
-> SELECT n + 1, f * (n + 1) FROM factorial WHERE n < 21
-> )
-> SELECT * FROM factorial;
ERROR 1690 (22003): BIGINT value is out of range in '(`factorial`.`f` * (`factorial`.`n` + 1))'
To calculate for bigger n, we can use DECIMAL.
mysql> WITH RECURSIVE factorial(n, f) AS (
-> SELECT 0, CAST(1 AS DECIMAL(65))
-> UNION ALL
-> SELECT n + 1, f * (n + 1) FROM factorial WHERE n < 50
-> )
-> SELECT * FROM factorial;
+------+-------------------------------------------------------------------+
| n | f |
+------+-------------------------------------------------------------------+
| 0 | 1 |
| 1 | 1 |
| 2 | 2 |
| 3 | 6 |
| 4 | 24 |
| 5 | 120 |
| 6 | 720 |
| 7 | 5040 |
| 8 | 40320 |
| 9 | 362880 |
| 10 | 3628800 |
| 11 | 39916800 |
| 12 | 479001600 |
| 13 | 6227020800 |
| 14 | 87178291200 |
| 15 | 1307674368000 |
| 16 | 20922789888000 |
| 17 | 355687428096000 |
| 18 | 6402373705728000 |
| 19 | 121645100408832000 |
| 20 | 2432902008176640000 |
| 21 | 51090942171709440000 |
| 22 | 1124000727777607680000 |
| 23 | 25852016738884976640000 |
| 24 | 620448401733239439360000 |
| 25 | 15511210043330985984000000 |
| 26 | 403291461126605635584000000 |
| 27 | 10888869450418352160768000000 |
| 28 | 304888344611713860501504000000 |
| 29 | 8841761993739701954543616000000 |
| 30 | 265252859812191058636308480000000 |
| 31 | 8222838654177922817725562880000000 |
| 32 | 263130836933693530167218012160000000 |
| 33 | 8683317618811886495518194401280000000 |
| 34 | 295232799039604140847618609643520000000 |
| 35 | 10333147966386144929666651337523200000000 |
| 36 | 371993326789901217467999448150835200000000 |
| 37 | 13763753091226345046315979581580902400000000 |
| 38 | 523022617466601111760007224100074291200000000 |
| 39 | 20397882081197443358640281739902897356800000000 |
| 40 | 815915283247897734345611269596115894272000000000 |
| 41 | 33452526613163807108170062053440751665152000000000 |
| 42 | 1405006117752879898543142606244511569936384000000000 |
| 43 | 60415263063373835637355132068513997507264512000000000 |
| 44 | 2658271574788448768043625811014615890319638528000000000 |
| 45 | 119622220865480194561963161495657715064383733760000000000 |
| 46 | 5502622159812088949850305428800254892961651752960000000000 |
| 47 | 258623241511168180642964355153611979969197632389120000000000 |
| 48 | 12413915592536072670862289047373375038521486354677760000000000 |
| 49 | 608281864034267560872252163321295376887552831379210240000000000 |
| 50 | 30414093201713378043612608166064768844377641568960512000000000000 |
+------+-------------------------------------------------------------------+
51 rows in set (0.00 sec)
And it won’t work for bigger n.
mysql> WITH RECURSIVE factorial(n, f) AS (
-> SELECT 0, CAST(1 AS DECIMAL(65))
-> UNION ALL
-> SELECT n + 1, f * (n + 1) FROM factorial WHERE n < 51
-> )
-> SELECT * FROM factorial;
ERROR 1264 (22003): Out of range value for column 'f' at row 1
Footnotes
1 https://www.percona.com/blog/2020/02/10/introduction-to-mysql-8-0-common-table-expressions-part-1/
2 https://www.percona.com/blog/2020/02/13/introduction-to-mysql-8-0-recursive-common-table-expression-part-2/