Как сделать дорожную сегментацию в SQL? - PullRequest
0 голосов
/ 28 февраля 2019

Я использую SQL Server 2012 У меня есть список дорог, каждый из которых имеет некоторую длину.Например, вот так:

Road  Length   
A         18
B         40
C         65

Я хочу разделить эти дороги на 20-километровые отрезки.поэтому таблица результатов выглядит следующим образом:

Road  From   To
A        0   18
B        0   20
B       20   40
C        0   20
C       20   40
C       40   60
C       60   65

Я думаю, мне нужно использовать цикл while, но я не знаю, как создать синтаксис.Только я смог сделать с моими навыками sql такой код:

DECLARE @t1 TABLE 
(
  Road VARCHAR(10)
  ,RoadLength INT
)
INSERT INTO @t1 VALUES ('A', 18)
INSERT INTO @t1 VALUES ('B', 40)
INSERT INTO @t1 VALUES ('C', 65)
;
DECLARE @t2 TABLE 
(
  Road VARCHAR(10)
  ,SectionFrom INT
  ,SectionTo INT
)
;
DECLARE @max AS INT
        ,@a AS INT
SET @max = (SELECT MAX(RoadLength) FROM @t1);
SET @a = 0;

 WHILE @a <= @max
 BEGIN
   INSERT INTO @t2 
     SELECT Road
            ,@a
            ,@a + 20 
     FROM @t1
   SET @a = @a + 20
 END
;
DELETE a
FROM @t2 a
join @t1 b ON a.Road = b.Road
WHERE a.SectionFrom >= b.RoadLength
;
UPDATE a SET SectionTo = b.RoadLength
FROM @t2 a
JOIN @t1 b ON a.Road = b.Road
WHERE a.SectionTo > b.RoadLength 
;
SELECT *
FROM @t2
ORDER BY Road, SectionFrom

Итак, для каждой дороги вставьте число участков для самой длинной дороги, затем я удалю эти дополнительные участки и обновлю последний раздел, которыйкороче 20 км.Результат удовлетворительный, но, конечно, код ужасный и очень медленный на больших объемах данных.

Есть предложения, как сделать это умнее?Спасибо!

1 Ответ

0 голосов
/ 28 февраля 2019

Здесь очень удобна таблица календаря.Мы можем определить таблицу (или CTE), которая содержит все сегменты, которые мы хотим отобразить в отчете.То есть каждая строка в этой «календарной» таблице будет содержать начальное и конечное расстояние, начиная с 0 до 20, затем с 20 до 40 и далее.

Затем все, что нам нужно сделать, это присоединиться к этомукалендарь таблицы к вашей таблице дорог:

WITH roads AS (
    SELECT 'A' AS Road, 18 AS Length UNION ALL
    SELECT 'B', 40 UNION ALL
    SELECT 'C', 65
),
sections AS (
    SELECT 0 AS start, 20 AS finish UNION ALL
    SELECT 20, 40 UNION ALL
    SELECT 40, 60 UNION ALL
    SELECT 60, 80 UNION ALL
    SELECT 80, 100
)

SELECT
    r.Road,
    s.start,
    CASE WHEN r.Length < s.finish THEN r.Length ELSE s.finish END AS finish
FROM sections s
INNER JOIN roads r
    ON s.start < r.Length;

enter image description here

Демо

Один комментарий к вышеупомянутому запросу заключается в том, что мы используем выражение CASE, чтобы решить, что сообщать в качестве конечного расстояния.Это связано с тем, что последний сегмент каждой дороги может не полностью совпадать с границей, кратной 20, которую мы используем для сегментов.Таким образом, мы всегда сообщаем меньшую длины дороги или конца отрезка.

...