Во-первых, давайте возьмем из этого примера пригодные для использования таблицы sqlite:
CREATE TABLE pavement(road TEXT, from_mile NUMERIC, to_mile NUMERIC, pavement TEXT);
INSERT INTO pavement VALUES('X',0,1,'Asphalt');
INSERT INTO pavement VALUES('X',1,3.5299999999999998046,'Gravel');
INSERT INTO pavement VALUES('X',3.5299999999999998046,5,'Asphalt');
CREATE TABLE quality(road TEXT, from_mile NUMERIC, to_mile NUMERIC, quality TEXT);
INSERT INTO quality VALUES('X',0,1.5,'Fine');
INSERT INTO quality VALUES('X',1.5,4,'Poor');
INSERT INTO quality VALUES('X',4,5,'Satisfactory');
CREATE TABLE traffic(road TEXT, from_mile NUMERIC, to_mile NUMERIC, traffic INTEGER);
INSERT INTO traffic VALUES('X',0,1.1999999999999999555,3055);
INSERT INTO traffic VALUES('X',1.1999999999999999555,2.7999999999999998223,1040);
INSERT INTO traffic VALUES('X',2.7999999999999998223,5,3600);
CREATE INDEX pavement_idx_road_from ON pavement(road, from_mile);
CREATE INDEX quality_idx_road_from ON quality(road, from_mile);
CREATE INDEX traffic_idx_road_from ON traffic(road, from_mile);
Теперь, когда у нас есть с чем поработать, первым шагом является получение интервалов пробега из всех трех таблиц (Примечание.требует sqlite 3.25 или новее, потому что он использует оконную функцию):
SELECT road, from_mile
, lead(from_mile, 1) OVER (PARTITION BY road ORDER BY from_mile) AS to_mile
FROM (SELECT road, from_mile FROM pavement
UNION
SELECT road, from_mile FROM quality
UNION
SELECT road, from_mile FROM traffic
UNION
SELECT road, max(to_mile) FROM pavement GROUP BY road);
дает нам
road from_mile to_mile
---------- ---------- ----------
X 0 1
X 1 1.2
X 1.2 1.5
X 1.5 2.8
X 2.8 3.53
X 3.53 4
X 4 5
X 5 (null)
По сути, он получает каждый уникальный from_mile
из трех таблиц и использует следующуюзначение в качестве конечной точки to_mile
для обозначения того, что будет уникальным разделом в окончательных результатах.
Следующий шаг - взять эти строки и соединить их со всеми тремя таблицами, чтобы получить необходимые поля длякаждый интервал пробега:
WITH ranges AS
(SELECT road, from_mile
, lead(from_mile, 1) OVER (PARTITION BY road ORDER BY from_mile) AS to_mile
FROM (SELECT road, from_mile FROM pavement
UNION
SELECT road, from_mile FROM quality
UNION
SELECT road, from_mile FROM traffic
UNION
SELECT road, max(to_mile) FROM pavement GROUP BY road))
SELECT r.road, r.from_mile, r.to_mile, q.quality, p.pavement, t.traffic
FROM ranges AS r
JOIN pavement AS p ON r.road = p.road AND p.from_mile <= r.from_mile AND p.to_mile >= r.to_mile
JOIN quality AS q ON r.road = q.road AND q.from_mile <= r.from_mile AND q.to_mile >= r.to_mile
JOIN traffic AS t ON r.road = t.road AND t.from_mile <= r.from_mile AND t.to_mile >= r.to_mile
ORDER BY r.road, r.from_mile;
, что дает:
road from_mile to_mile quality pavement traffic
---------- ---------- ---------- ---------- ---------- ----------
X 0 1 Fine Asphalt 3055
X 1 1.2 Fine Gravel 3055
X 1.2 1.5 Fine Gravel 1040
X 1.5 2.8 Poor Gravel 1040
X 2.8 3.53 Poor Gravel 3600
X 3.53 4 Poor Asphalt 3600
X 4 5 Satisfacto Asphalt 3600
(Не берите в голову усечение длинных полей на дисплее; вот как я копирую оболочку sqlite3форматирует вещи)