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

TSQL迭代表中的子集-根据组更新值,sql,sql-server,tsql,sql-update,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

我有一个包含多组记录的大表。 我需要对内部组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
对于每个组,我需要执行以下操作:

获取该组N的记录数 获取包含“拆分”数据的记录的位置 将拆分位置的ID更改为原始+N 在ID为Split+N+1和Split+N+2的每个组中添加两行 将拆分后的Id更改为原始+N+2 最终结果应该是

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
)

我知道上面的内容不存在,但我如何才能获得相同的功能?

我想这样就可以了

declare @t table (idx int, grp int, id int, data varchar(10));
insert into @t values  
       (001,    01,       01, null)      
     , (002,    01,       02, null)          
     , (003,    01,       03, 'Split')
     , (004,    01,       04, null)    
     , (005,    02,       01, null)           
     , (006,    02,       02, 'Split')
     , (007,    02,       03, null)    
     , (008,    02,       04, null)    
     , (009,    02,       05, null)    
     , (100,    03,       01, null)           
     , (101,    03,       02, null)    
     , (102,    03,       03, null)    
     , (103,    03,       04, 'Split')
     , (104,    03,       05, null);
with cte as 
(  select t.* 
        , count(*)     over (partition by t.grp) as cnt 
        , row_number() over (partition by t.grp order by t.id, t.idx) as rn 
        , (count(*) over (partition by t.grp) + t.id) as nwId  
        , ts.id as 'split' 
        , CASE WHEN t.id > ts.id THEN (count(*) over (partition by t.grp) + t.id + 2) 
                                 ELSE (count(*) over (partition by t.grp) + t.id) 
               end as nwnwId
     from @t t
     left join @t ts 
       on ts.grp = t.grp 
      and ts.data = 'split' 
)
select t.* 
 from cte t  
union all 
select t.idx, t.grp, t.id, null, t.cnt, t.rn, t.nwId, t.split, t.nwnwId + 1
 from cte t 
where t.data = 'split'
union all 
select t.idx, t.grp, t.id, null, t.cnt, t.rn, t.nwId, t.split, t.nwnwId + 2
 from cte t 
where t.data = 'split'
 order by grp, nwnwId, idx;

使用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
编辑:

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

也稍微快一点

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

也许展示你想要的结果可以帮助其他人理解问题注:我没有否决这个问题,我已经相应地更新了帖子。我希望人们能解释他们为什么否决投票。。。我努力正确地表达了这个问题:是否保证只有一次拆分?@Papazzi-是的,应该只有一次拆分。每个组的输出应该有两行新项目。@MatBailie见第一行。不完整,但大约为1/2there@Paparazzi过度分区让人大开眼界——我不知道这个函数。此外,WITH的使用方式与课堂解决方案不同。谢谢,太好了!我已经用INSERT将最后两个选择插入到另一个表中,并得到了最终结果。谢谢