Someone posted an SQL question in a forum I occasionally frequent. The setup:
CREATE TABLE tbl (num INTEGER); INSERT INTO tbl VALUES ( 1); INSERT INTO tbl VALUES ( 2); INSERT INTO tbl VALUES ( 3); INSERT INTO tbl VALUES ( 4); INSERT INTO tbl VALUES ( 9); INSERT INTO tbl VALUES ( 10); INSERT INTO tbl VALUES ( 11); INSERT INTO tbl VALUES ( 20); INSERT INTO tbl VALUES ( 21); INSERT INTO tbl VALUES ( 22); INSERT INTO tbl VALUES ( 23); INSERT INTO tbl VALUES (100); INSERT INTO tbl VALUES (101); INSERT INTO tbl VALUES (102); INSERT INTO tbl VALUES (103);
His question: is there a way to produce the following output?
start end ---------- ---------- 1 4 9 11 20 23 100 103
I didn’t think it was possible at first, but after some thinking and tinkering, I managed to come up with a solution:
SELECT s.num AS start, MIN( e.num ) AS end FROM ( SELECT num FROM tbl t1 WHERE NOT EXISTS ( SELECT NULL FROM tbl t2 WHERE t2.num = t1.num - 1 ) ORDER BY num ) s CROSS JOIN ( SELECT num FROM tbl t1 WHERE NOT EXISTS ( SELECT NULL FROM tbl t2 WHERE t2.num = t1.num + 1 ) ORDER BY num ) e WHERE s.num <= e.num GROUP BY s.num;
Re:Cross JOIN
Aristotle on 2007-03-29T06:39:59
CROSS JOIN
is simply an explicit way to request the standard cartesian product.sqlite> CREATE TABLE tbl (num INTEGER);
sqlite> INSERT INTO tbl VALUES ( 1);
sqlite> INSERT INTO tbl VALUES ( 2);
sqlite> INSERT INTO tbl VALUES ( 3);
sqlite> SELECT t1.num A, t2.num B FROM tbl t1 CROSS JOIN tbl t2;
A B
---------- ----------
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3You can write the exact same query like this:
SELECT t1.num A, t2.num B FROM tbl t1, tbl t2I just prefer the newer syntax because there are few cases where you’d deliberately ask for a cartesian product, and with the old syntax it’s not clear whether you did so or merely forgot the join condition. The new explicit syntax documents your intent.