TSQL迭代表中的子集 - 根据组更新值

时间:2018-03-04 15:05:25

标签: sql sql-server tsql sql-update

我有一个包含记录组的大表。 我需要更改内部组ID - 我想为每个组单独运行此过程

示例数据

Index  Group    InternalID  Data
001    01       01       
002    01       02      
003    01       03      Split
004    01       04
005    02       01       
006    02       02      Split
007    02       03
008    02       04
009    02       05
100    03       01       
101    03       02
102    03       03
103    03       04      Split
104    03       05

对于每个小组,我需要执行以下操作:

  1. 获取该组的记录数(N)
  2. 使用' Split'获取记录的位置数据(S)
  3. 将ID更改为分割位置为原始+ N
  4. 为每个组添加两行,ID为“Split + N + 1”和“Split + N + 2”
  5. 将分割后的ID更改为原始+ N + 2
  6. 最终结果应为

    Group        InternalID      Data
    01           05
    01           06
    01           07              Split
    01           08              NewItem1
    01           09              NewItem2
    01           10              
    02           06
    02           07              Split
    02           08              NewItem1
    02           09              newItem2
    02           10 
    02           11
    02           12
    03           06
    03           07
    03           08
    03           09              Split
    03           10              NewItem1
    03           11              NewItem2
    03           12
    

    我想它看起来像[当心伪代码!!!不是真正的SQL!]

    Declare @GCount VARCHAR(10)
        @GSplit VARCHAR(10)
    
    CREATE TABLE ##temp (
        Idx int,
        Grp int,
        InternalID int, 
        Data varchar (10)
    
    FOREACH [Group] from [Example]
    
            Select @GCount = COUNT(InternalID)
            Select @GSplit = (select InternalID from [Example] where [Data]='Split')
            Insert Into ##temp 
                Select Grp, Data,
                CASE WHEN InternalID <= @GSplit THEN InternalID + @GCount
                ELSE THEN InternalID+@GCount+2
                END AS InternalID
            INSERT INTO ##temp 
                VALUES (00,[Group],@GSplit + @GCount + 1, 'NewItem1'),  (01,[Group],@GSplit + @GCount + 2, 'NewItem2')
     END FOREACH
    
    UPDATE  
        [Example]
    SET 
        [Example].* = ##temp.*
    FROM 
        ##temp
    OUTER JOIN
        [Example]
    ON
        ##temp.Idx=[Example].Idx
    
    
    IF OBJECT_ID('tempdb..##temp') IS NOT NULL
    
    BEGIN
    
        Drop Table ##temp
    
    END
    )
    

    我知道上面不存在,但我怎样才能获得相同的功能?

2 个答案:

答案 0 :(得分:1)

使用Windows函数找出拆分的位置以及组的大小。

根据拆分行添加新行。这可以确保您知道要应用的ID,以及仅添加实际为拆分的行。

使用算术和CASE计算出正确的id值。

WITH
  summarised AS
(
  SELECT
    *,
    MAX([InternalID])
      OVER (PARTITION BY [group])                             AS GroupMaxID,
    MAX(CASE WHEN [data] = 'split' THEN [InternalID] END)
      OVER (PARTITION BY [group])                             AS GroupSplitID
  FROM
    yourData
)
SELECT
  [group],
  GroupMaxID
    + InternalID
    + CASE WHEN InternalID > GroupSplitID THEN 2 ELSE 0 END   AS InternalID,
  [data]
FROM
  summarised

UNION ALL

SELECT
  summarised.[group],
  summarised.GroupMaxID
    + summarised.InternalID
    + NewRows.Offset,
  NewRows.datum
FROM
  summarised
CROSS APPLY
(
  SELECT 1 AS offset, 'NewItem1' AS datum
  UNION ALL
  SELECT 2 AS offset, 'NewItem2' AS datum
)
  AS NewRows
WHERE
  summarised.[data] = 'split'

ORDER BY
  1, 2

http://sqlfiddle.com/#!18/91d7c/3

<强> 编辑:

相同逻辑的稍微更短且更一致的实现:

http://sqlfiddle.com/#!18/d56f1/1

也非常快。

WITH
  summarised AS
(
  SELECT
    *,
    MAX([InternalID])
      OVER (PARTITION BY [group])                             AS GroupMaxID,
    MAX(CASE WHEN [data] = 'split' THEN [InternalID] END)
      OVER (PARTITION BY [group])                             AS GroupSplitID
  FROM
    yourData
)
SELECT
  summarised.[group]           AS [group],
  summarised.GroupMaxID
    + summarised.InternalID
    + NewRows.Offset           AS InternalID,
  NewRows.[data]               AS [data]
FROM
  summarised
CROSS APPLY
(
  SELECT 0 AS offset, summarised.[data] WHERE summarised.InternalID <= summarised.GroupSplitID
  UNION ALL
  SELECT 1 AS offset, 'NewItem1'        WHERE summarised.InternalID  = summarised.GroupSplitID
  UNION ALL
  SELECT 2 AS offset, 'NewItem2'        WHERE summarised.InternalID  = summarised.GroupSplitID
  UNION ALL
  SELECT 2 AS offset, summarised.[data] WHERE summarised.InternalID >  summarised.GroupSplitID
)
  AS NewRows
ORDER BY
  summarised.[group],
  summarised.InternalID,
  NewRows.Offset

答案 1 :(得分:0)

我认为这样做会

flintlabel['text'] = "Flint: "  + str(flint)