将表中的一行拆分为多行

时间:2018-04-07 02:42:19

标签: sql-server tsql

我有一个表,列表中有一个日期,唯一的ID是(日期,时间和参考的连接)。加上一个包含数字f项的列。

BEFORE

我希望能够将这些数据分成如下图所示。因此,上面数据中的每一行都会根据列出的项目数进行拆分。对于例如' 142691'有11个项目,所以我想把它分成11个项目,但

正如您所看到的那样,创建了唯一ID,因为某些引用可以有多个条目,例如' 142692'对于每个条目,时间增加一分钟。

AFTER SPLIT

如果有人可以提供帮助,我将不胜感激。

我尝试了以下内容:

DECLARE @COUNT INT
        SET @count = 0

        DECLARE @add TABLE (ID BIGINT, REF INT, DATE INT, PERIOD INT, TIME VARCHAR(12), ITEMS INT)

        WHILE (@count < (SELECT DURATION FROM @add))

            BEGIN
                INSERT INTO @add
                SELECT @COUNT   
                SET @count = (@count + 1)
            END

        DECLARE @SPLITRW TABLE (ID BIGINT, REF INT, DATE INT, PERIOD INT, TIME VARCHAR(12), ITEMS INT)

        INSERT INTO @SPLITRW 
        (ID, REF, DATE, PERIOD,TIME, ITEMS)
        SELECT ID, REF, DATE, PERIOD, (TIME + @COUNT), ITEMS
        FROM dbo.dataset

        SELECT ID, REF, DATE, PERIOD, TIME , items
        FROM @SPLITRW SR
        INNER JOIN @add AD
        ON AD.ID BETWEEN 1 AND AD.items

2 个答案:

答案 0 :(得分:3)

如果您没有数字或计数表,则可以使用临时计数表。

示例

Select A.ID
      ,A.Ref
      ,A.Date
      ,A.Period
      ,Time=dateadd(MINUTE,N,A.Time)
      ,A.Items
 From  YourTable A
 Join ( Select Top 1000 N=Row_Number() Over (Order By (Select NULL))-1 
         From  master..spt_values n1, master..spt_values n2 
      ) B on B.N<=A.Items

您可能会注意到子查询中的**Select TOP 1000**。您可以将其调整为更合理/最大的数字。或者你可以

 ...
 Join ( Select Top (Select 1+max(Items) from YourTable) N=Row_Number() Over (Order By (Select NULL))-1 
         From  master..spt_values n1, master..spt_values n2 
      ) B on B.N<=A.Items
  

编辑 - 按要求

使用spt_values的子查询(可以是任何适当大小的表)只需生成一个从0到9999的临时计数表。然后我们只需将数据加入ITEMS的限制即可创建1-many。我们还使用N来增加你的TIME。

答案 1 :(得分:3)

我相信这会回答你的问题。

我从名为Multiplier的递归CTE开始,它为每个ID保留等于ITEMS值+1的行。 RN(行数)值从0开始并递增到ITEMS。如果您怀疑的行数太多,请将WHERE RN < ITEMS更改为WHERE RN < ITEMS-1

样本CTE数据:

ID                      ITEMS   RN
20180403165100142691    11      0
20180403165100142691    11      1
20180403165100142691    11      2
20180403165100142691    11      3
20180403165100142691    11      4
20180403165100142691    11      5
20180403165100142691    11      6
20180403165100142691    11      7
20180403165100142691    11      8
20180403165100142691    11      9
20180403165100142691    11      10
20180403165100142691    11      11

从那里,我们JOIN将CTE返回到ID上的主表,并对日期/时间字段进行一些操作,每行增加1分钟(添加RN })。

DECLARE @Test TABLE (ID VARCHAR(100), REF INT, [DATE] VARCHAR(10), [PERIOD] INT, [TIME] TIME, NUM INT, ITEMS INT)
INSERT INTO @Test 
VALUES ('20180403165100142691',142691,'20180403',37,'16:51',NULL,11)
       ,('20180403165500142692',142692,'20180403',37,'16:55',NULL,15)
       ,('20180403171000142692',142692,'20180403',37,'17:15',NULL,8)
       ,('20180403170700142693',142693,'20180403',37,'17:07',NULL,20)
       ,('20180403235700142693',142693,'20180403',37,'23:57',NULL,7)

;WITH Multiplier AS 
(
    SELECT ID, ITEMS, 0 AS RN
    FROM @Test
    UNION ALL
    SELECT ID, ITEMS, RN+1
    FROM Multiplier
    WHERE RN < ITEMS
)

SELECT T.ID, 
       T.REF, 
       CONVERT(VARCHAR(10),DATEADD(MINUTE,RN,CONVERT(DATETIME,T.[DATE])+CONVERT(DATETIME,T.[TIME])),112) AS [DATE], 
       T.[PERIOD], 
       CONVERT(VARCHAR(5),DATEADD(MINUTE,RN,T.[TIME]),108) AS [TIME], 
       T.NUM, 
       T.ITEMS
FROM @Test T
JOIN Multiplier I ON T.ID=I.ID
ORDER BY T.ID, T.[TIME]