表中重复行 (x) 的次数

jew*_*g97 4 sql-server sql-server-2016

我有一张如下所示的表:

?????????????????????????????????
?      SO  ?   SO_Line ?  ...   ? 
?????????????????????????????????
?      ABC ?        1  ?        ?
?      ABC ?        3  ?        ?
?      ABC ?        5  ?        ?
?      DEF ?        1  ?        ?
?      DEF ?        2  ?        ?
?????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

我想做的是复制结果集 (x) 次。例如,给定这个结果集:SELECT * FROM Table WHERE SO = 'ABC',我想将该结果集复制 10 次。基本上我想保持所有其他列中的所有数据相同,但我会将主键更改为其他内容(例如,ABC-1)。复制该集合后,我的最终表将是这样的:

?????????????????????????????????
?      SO  ?   SO_Line ?  ...   ? 
?????????????????????????????????
?      ABC ?        1  ?  ...   ?
?      ABC ?        3  ?  ...   ?
?      ABC ?        5  ?  ...   ?
?    ABC-1 ?        1  ?  ...   ?
?    ABC-1 ?        3  ?  ...   ?
?    ABC-1 ?        5  ?  ...   ?
?????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

通常,我这样做的方法是将结果集中的记录插入到临时表中,然后为每一行分配一个行号。然后我会使用类似的东西遍历临时表WHILE @i < @RowCount,并使用@i增加 PK对主表进行插入。我基本上是在问 A) 这是否是实现此目标的最合理方法,如果不是,B) 是否有更有效的处理方法?

McN*_*ets 7

您可以使用表值或值列表以及CROSS JOIN来获取它。

INSERT INTO foo
SELECT CONCAT(SO, t.x) as SO, SO_Line
FROM   foo
CROSS JOIN (VALUES('-1'),('-2'),('-3'),('-4'),('-5')) t(x)
WHERE  SO = 'ABC';
GO
Run Code Online (Sandbox Code Playgroud)
15 行受影响
SELECT * FROM   foo;
GO
Run Code Online (Sandbox Code Playgroud)
所以 | SO_线
:---- | ------:
ABC | 1
ABC | 3
ABC | 5
防御 | 1
防御 | 2
ABC-1 | 1
ABC-2 | 1
ABC-3 | 1
ABC-4 | 1
ABC-5 | 1
ABC-1 | 3
ABC-2 | 3
ABC-3 | 3
ABC-4 | 3
ABC-5 | 3
ABC-1 | 5
ABC-2 | 5
ABC-3 | 5
ABC-4 | 5
ABC-5 | 5

dbfiddle在这里

您可以使用INLINE 用户定义的函数,而不是使用值列表:

CREATE FUNCTION tvValues(@Num int)
RETURNS table
AS
RETURN 
(
     SELECT TOP (@Num) ROW_NUMBER() OVER (ORDER BY S.[object_id]) [item]
     FROM    sys.all_objects S
)
GO
Run Code Online (Sandbox Code Playgroud)

然后将您的查询转换为:

INSERT INTO foo
SELECT CONCAT(SO, '-', t.item) as SO, SO_Line
FROM   foo
CROSS JOIN tvValues(7) t
WHERE  SO = 'ABC';
GO
Run Code Online (Sandbox Code Playgroud)

注意:我已经使用过,tvValues(7)但您可以使用其他值。

这是结果:

SELECT * FROM   foo;
GO
Run Code Online (Sandbox Code Playgroud)
所以 | SO_线
:---- | ------:
ABC | 1
ABC | 3
ABC | 5
防御 | 1
防御 | 2
ABC-1 | 1
ABC-2 | 1
ABC-3 | 1
ABC-4 | 1
ABC-5 | 1
ABC-6 | 1
ABC-7 | 1
ABC-1 | 3
ABC-2 | 3
ABC-3 | 3
ABC-4 | 3
ABC-5 | 3
ABC-6 | 3
ABC-7 | 3
ABC-1 | 5
ABC-2 | 5
ABC-3 | 5
ABC-4 | 5
ABC-5 | 5
ABC-6 | 5
ABC-7 | 5

dbfiddle在这里