TSQL迭代表中的子集 - 根据组更新值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TSQL迭代表中的子集 - 根据组更新值相关的知识,希望对你有一定的参考价值。
我有一个包含记录组的大表。我需要更改内部组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)
- 使用“拆分”数据获取记录的位置(S)
- 将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
)
我知道上面不存在,但我怎样才能获得相同的功能?
答案
使用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
另一答案
我想这会做到的
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;
以上是关于TSQL迭代表中的子集 - 根据组更新值的主要内容,如果未能解决你的问题,请参考以下文章
MySQL在1个表中选择不同的记录并根据另一个表中的值计算每个组