Объединить несколько листов Excel с перекрывающимися данными - PullRequest
2 голосов
/ 29 апреля 2019

У меня есть несколько файлов Excel, описывающих дорожную сеть.Возьмем, к примеру, 3 (реальные файлы довольно большие и с большим количеством записей):

Описание дорожного покрытия:

Road From To Pavement
    X 0,00 1,00 Asphalt
    X 1,00 3,53 Gravel
    X 3,53 5,00 Asphalt 

Описание качества:

Road From To Quality
    X 0,00 1,50 Fine
    X 1,50 4,00 Poor
    X 4,00 5,00 Satisfactory

Описание трафикатом:

 Road From To Traffic
     X 0,00 1,20 3055
     X 1,20 2,80 1040
     X 2,80 5,00 3600

Я хочу объединить все эти файлы и получить результат со всеми возможными данными (очевидно, разделенными на несколько разделов).Вот так:

Road From To Quality Pavement Traffic
    X 0,00 1,00 Fine Asphalt 3055
    X 1,00 1,20 Fine Gravel 3055
    X 1,20 1,50 Fine Gravel 1040
    X 1,50 2,80 Poor Gravel 1040
    X 2,80 3,53 Poor Gravel 3600
    X 3,53 4,00 Poor Asphalt 3600
    X 4,00 5,00 Satisfactory Asphalt 3600

Не знаю, как это сделать.Пытался прочитать все доступные данные с помощью openpyxl (Python), чтобы собрать все данные в базе данных Sqlite, но я не представляю, как правильно выбрать данные.Пробовал сортировку, группировку и пока ничего.Есть идеи?

1 Ответ

0 голосов
/ 29 апреля 2019

Во-первых, давайте возьмем из этого примера пригодные для использования таблицы 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форматирует вещи)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...