如何在SQL中进行路段分割?

时间:2019-02-28 13:14:32

标签: while-loop sql-server-2012

我正在使用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 :(得分:0)

日历表在这里确实派上用场。我们可以定义一个表(或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

Demo

对上述查询的一个评论是,我们使用CASE表达式来决定要报告的终点距离。这是因为每条道路的最终路段可能与我们用于路段的20的倍数边界不完全一致。因此,我们总是报告道路长度或路段终点的较小