sql server如何解压数据

sql server如何解压数据,sql,sql-server,Sql,Sql Server,我想对同一组中的数据进行解压 让我举例说明 演示数据: +-------------+----+------------+-----------+ | Primarykey | ID | START_Point| STOP_Point| +-------------+----+------------+-----------+ | 1 | 1 | 1 | 10 | | 2 | 1 | 2 |

我想对同一组中的数据进行解压

让我举例说明

演示数据:

 +-------------+----+------------+-----------+
|  Primarykey | ID | START_Point| STOP_Point|
+-------------+----+------------+-----------+
|           1 |  1 |          1 |        10 |
|           2 |  1 |          2 |         4 |
|           3 |  1 |          5 |         5 |
|           4 |  1 |          5 |         5 |
|           5 |  1 |          5 |        15 |
|           6 |  2 |          5 |         5 |
|           7 |  2 |          2 |         2 |
|           8 |  2 |          1 |        10 |
|           9 |  2 |          1 |        20 |
+-------------+----+------------+-----------+
数据应与组中的数据解套:

预期产出:

+------------+-----------+------------+-----------+
| primarykey | SubjectID | START_Point| STOP_Point|
+------------+-----------+------------+-----------+
|          1 |         1 |          1 |         1 |
|          1 |         1 |          2 |         4 |
|          1 |         1 |          5 |         5 |
|          1 |         1 |          6 |        10 |
|          2 |         1 |          2 |         4 |
|          3 |         1 |          5 |         5 |
|          4 |         1 |          5 |         5 |
|          5 |         1 |          5 |         5 |
|          5 |         1 |          6 |        10 |
|          5 |         1 |         11 |        15 |
|          6 |         2 |          5 |         5 |
|          7 |         2 |          2 |         2 |
|          8 |         2 |          1 |         1 |
|          8 |         2 |          2 |         2 |
|          8 |         2 |          3 |         4 |
|          8 |         2 |          5 |         5 |
|          8 |         2 |          6 |        10 |
|          9 |         2 |          1 |         1 |
|          9 |         2 |          2 |         2 |
|          9 |         2 |          3 |         4 |
|          9 |         2 |          5 |         5 |
|          9 |         2 |          6 |        10 |
|          9 |         2 |         11 |        20 |
+------------+-----------+------------+-----------+
逻辑: 同一组中不应有任何重叠的起始点-停止点范围

说明:

按“ID”分组

对于主键=1

我们有起点=1和终点=10

现在,如果我们检查其他行的ID=1(因为groupbyid),那么我们可以看到 主键2、3、4和5哪个数据在1-10范围内重叠


所以我们想从1-10到1-1,2-4,5-5,6-10去崩塌

每行应用相同的逻辑

我不想使用游标或逐行获取和处理逻辑,因为我的查询将应用于批量数据,这将降低处理速度

请让我知道,如果我没有解释任何事情或任何事情看起来困惑你

这有点挑战性,但我知道我们有很多关于堆栈溢出的专家

寻找一些固溶体


提前感谢。

您可以使用以下查询作为起点:

SELECT ID, Idx, StartStop, 
       LEAD(Idx) OVER (PARTITION BY ID ORDER BY IdxRowNum) AS NextIdx,
       LEAD(StartStop) OVER (PARTITION BY ID ORDER BY IdxRowNum) AS NextStartStop
FROM (
    SELECT ID, Idx, StartStop, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Idx, StartStop) AS IdxRowNum                         
    FROM
      (SELECT ID, START_Point, STOP_Point
       FROM @T) Src
    UNPIVOT (
      Idx FOR StartStop IN (START_Point, STOP_Point)
    ) AS Unpvt
) t
为原始表中包含的每个ID的每个时间跨度创建一个起点-终点表

使用上述查询作为基础,您可以获得每个ID的所有现有间隔:

SELECT DISTINCT ID, StartIdx, StopIdx
FROM
(
    SELECT ID, 
           CASE 
             WHEN StartStop = 'START_Point' AND NextStartStop = 'START_Point' THEN 
                CASE WHEN NextIdx > Idx THEN Idx ELSE NULL END
             WHEN StartStop = 'STOP_Point' AND NextStartStop = 'STOP_Point' THEN 
                CASE WHEN NextIdx > Idx THEN Idx + 1 ELSE NULL END
             WHEN StartStop = 'STOP_Point' AND NextStartStop = 'START_Point' THEN 
                CASE WHEN NextIdx > Idx THEN Idx + 1 ELSE NULL END
             WHEN StartStop = 'START_Point' AND NextStartStop = 'STOP_Point' THEN Idx           
           END AS StartIdx, 
           CASE 
             WHEN StartStop = 'START_Point' AND NextStartStop = 'START_Point' THEN 
                CASE WHEN NextIdx > Idx THEN NextIdx - 1 ELSE NULL END
             WHEN StartStop = 'STOP_Point' AND NextStartStop = 'STOP_Point' THEN 
                CASE WHEN NextIdx > Idx THEN NextIdx ELSE NULL END
             WHEN StartStop = 'START_Point' AND NextStartStop = 'STOP_Point' THEN NextIdx
             WHEN StartStop = 'STOP_Point' AND NextStartStop = 'START_Point' THEN 
                CASE WHEN NextIdx = Idx + 1 THEN NextIdx WHEN NextIdx > Idx THEN NextIdx- 1 ELSE NULL END
             ELSE Idx
           END AS StopIdx
    FROM
    (
        SELECT ID, Idx, StartStop, 
               LEAD(Idx) OVER (PARTITION BY ID ORDER BY IdxRowNum) AS NextIdx,
               LEAD(StartStop) OVER (PARTITION BY ID ORDER BY IdxRowNum) AS NextStartStop
        FROM (
            SELECT ID, Idx, StartStop, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Idx, StartStop) AS IdxRowNum                         
            FROM
              (SELECT ID, START_Point, STOP_Point
               FROM @T) Src
            UNPIVOT (
              Idx FOR StartStop IN (START_Point, STOP_Point)
            ) AS Unpvt
        ) t
    ) s
) u
WHERE StartIdx IS NOT NULL AND StopIdx IS NOT NULL
上述查询的输出为:

ID  StartIdx StopIdx
-----------------------
1   1        1
1   2        4
1   5        5
1   6        10
1   11       15
2   1        1
2   2        2
2   3        4
2   5        5
2   6        10
2   11       20
在CTE中使用前面的查询并执行
交叉应用
最终得到您想要的:

; WITH IntervalsByID AS
(
    SELECT DISTINCT ID, StartIdx, StopIdx
    FROM
    (
        SELECT ID, 
               CASE 
                 WHEN StartStop = 'START_Point' AND NextStartStop = 'START_Point' THEN 
                    CASE WHEN NextIdx > Idx THEN Idx ELSE NULL END
                 WHEN StartStop = 'STOP_Point' AND NextStartStop = 'STOP_Point' THEN 
                    CASE WHEN NextIdx > Idx THEN Idx + 1 ELSE NULL END
                 WHEN StartStop = 'STOP_Point' AND NextStartStop = 'START_Point' THEN 
                    CASE WHEN NextIdx > Idx THEN Idx + 1 ELSE NULL END
                 WHEN StartStop = 'START_Point' AND NextStartStop = 'STOP_Point' THEN Idx           
               END AS StartIdx, 
               CASE 
                 WHEN StartStop = 'START_Point' AND NextStartStop = 'START_Point' THEN 
                    CASE WHEN NextIdx > Idx THEN NextIdx - 1 ELSE NULL END
                 WHEN StartStop = 'STOP_Point' AND NextStartStop = 'STOP_Point' THEN 
                    CASE WHEN NextIdx > Idx THEN NextIdx ELSE NULL END
                 WHEN StartStop = 'START_Point' AND NextStartStop = 'STOP_Point' THEN NextIdx
                 WHEN StartStop = 'STOP_Point' AND NextStartStop = 'START_Point' THEN 
                    CASE WHEN NextIdx = Idx + 1 THEN NextIdx WHEN NextIdx > Idx THEN NextIdx- 1 ELSE NULL END
                 ELSE Idx
               END AS StopIdx
        FROM
        (
            SELECT ID, Idx, StartStop, 
                   LEAD(Idx) OVER (PARTITION BY ID ORDER BY IdxRowNum) AS NextIdx,
                   LEAD(StartStop) OVER (PARTITION BY ID ORDER BY IdxRowNum) AS NextStartStop
            FROM (
                SELECT ID, Idx, StartStop, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Idx, StartStop) AS IdxRowNum                         
                FROM
                  (SELECT ID, START_Point, STOP_Point
                   FROM @T) Src
                UNPIVOT (
                  Idx FOR StartStop IN (START_Point, STOP_Point)
                ) AS Unpvt
            ) t
        ) s
    ) u
    WHERE StartIdx IS NOT NULL AND StopIdx IS NOT NULL
)
SELECT t.PrimaryKey, t.ID, s.StartIdx, s.StopIdx
FROM @T AS t
CROSS APPLY 
( 
   SELECT * 
   FROM IntervalsByID
   WHERE ID = t.ID AND t.START_Point <= StartIdx AND t.STOP_Point >= StopIdx
) s   
ORDER BY PrimaryKey, StartIdx

因此,我们要将1-10解折叠为1-1,2-4,5-5,6-10。这是如何完成的?
primarykey=5
起点和
终点显示为5-15。它是如何变成
6-10
?对于
id=2
,它将如何工作?我们可以帮助您找到解决方案。但首先你需要提供问题的细节。您试图以某种方式扩展数据,但我们不了解业务规则是什么。从你发布的内容来看,这对我来说毫无意义。“decollapse”不是一个词,我想你的意思是扩展。每一行都有一个唯一的键吗?@user2315555,5-15应该扩展到5-5,6-10和11-15,因为已经有一个范围5-5和1-10,所以我们需要将5-15拆分为5-5(我们有一行5-5),6-10(我们有一行1-10)和11-15。。。你的解决方案很有魅力。非常感谢。。你真是个明星。。这个问题看起来很简单,但它的解决方案同样复杂。你运用了很好的逻辑…请让我知道我是否可以在任何网站或博客上关注你。。再次非常感谢。。。
    PrimaryKey  ID  StartIdx    StopIdx
   --------------------------------------
    1           1   1           1
    1           1   2           4
    1           1   5           5
    1           1   6           10
    2           1   2           4
    3           1   5           5
    4           1   5           5
    5           1   5           5
    5           1   6           10
    5           1   11          15
    6           2   5           5
    7           2   2           2
    8           2   1           1
    8           2   2           2
    8           2   3           4
    8           2   5           5
    8           2   6           10
    9           2   1           1
    9           2   2           2
    9           2   3           4
    9           2   5           5
    9           2   6           10
    9           2   11          20