Reputation: 37
How do I copy few rows from one SQL Server table into many rows in another? Table1
has a [Qty]
column. I want to copy every row from Table1
into Table2
, each row copied [Qty]
times.
Sample data:
crdCard
:
CardID Qty CardName
------------------------
1 4 Lose A Turn
2 3 Collect $100
3 2 Bonus Roll
4 1 Golden Parachute
This represents 10 cards. I want to copy into another table as 10 rows:
crdShuff
ShuffID RoundID CardID
-------------------------------
1 1 1 (Lose A Turn)
2 1 1 (Lose A Turn)
3 1 1 (Lose A Turn)
4 1 1 (Lose A Turn)
5 1 2 (Collect $100)
6 1 2 (Collect $100)
7 1 2 (Collect $100)
8 1 3 (Bonus Roll)
9 1 3 (Bonus Roll)
10 1 4 (Golden Parachute)
My procedure:
crdShuffleDeck
begin
declare @RoundID int
set @RoundID = isnull((select max(RoundID) from crdShuffle), 0) + 1
-- TEMP TABLE...
create table #temp1(CardID int, Qty int)
-- SEED...
select @CardID = min(CardID) from crdCard
-- LOOP ALL CARDS...
while (@CardID > 0)
begin
-- GET QTY...
select @Qty = Qty from crdCard where CardID = @CardID
-- INSERT THAT MANY TIMES...
while (@Qty > 0)
begin
-- ADD CARD ROW...
insert into #temp1(CardID, Qty)
values(@CardID, @Qty)
-- DECREMENT...
set @Qty = @Qty - 1
end
-- FIND NEXT CARD...
set @CardID = isnull((select min(cd.CardID) from crdCard cd where cd.CardID > @CardID), 0)
end
-- DEBUG... * THIS RETURNS THE CORRECT @RoundID (1) & NUMBER OF ROWS (10). *
select t.CardID
, @RoundID
from #temp1 t
-- SHUFFLE INTO PERMANENT TABLE...
insert into crdShuffle(RoundID
, CardID)
select @RoundID
, t.CardID
from #temp1 t
--order by NEWID()
end
My real data is 29 rows defining 114 cards. This procedure returns 228 or 342 rows seemingly randomly. Rows returned include Round #1 and Round #2 which I assume can only happen if this procedure is called twice or somehow calls itself. When it returns 342 rows there's still only Round #1 and #2, no #3s.
I've tried the SHUFFLE INTO PERMANENT TABLE portion as a loop too, copying one row at a time. No matter what I do I end up with 2x or 3x rows.
I'm utterly stumped. I am convinced it's a quirk/bug of SQL Server.
Upvotes: 1
Views: 90
Reputation: 10205
If using SQL Server 2022 or later, you can use GENERATE_SERIES()
to act as a row multiplier.
SELECT
ROW_NUMBER() OVER(ORDER BY C.cardId, S.value) as ShuffID,
@RoundID AS RoundID,
C.CardID,
C.CardName
FROM crdCard C
CROSS APPLY GENERATE_SERIES(1, C.Qty) S
WHERE C.Qty > 0 -- Needed if Qty might be zero
The ROW_NUMBER()
calculation for ShuffID
is included for demo purposes. Omit that select item if ShuffID
is an IDENTITY
column in the target table.
Results:
ShuffID | RoundID | CardID | CardName |
---|---|---|---|
1 | 1 | 1 | Lose A Turn |
2 | 1 | 1 | Lose A Turn |
3 | 1 | 1 | Lose A Turn |
4 | 1 | 1 | Lose A Turn |
5 | 1 | 2 | Collect $100 |
6 | 1 | 2 | Collect $100 |
7 | 1 | 2 | Collect $100 |
8 | 1 | 3 | Bonus Roll |
9 | 1 | 3 | Bonus Roll |
10 | 1 | 4 | Golden Parachute |
See this db<>fiddle for a demo of the above SELECT
or this one showing repeated executions that insert into crdShuffle
.
Upvotes: 3
Reputation: 522509
We can handle your requirement using a join approach with the help of a sequence table. Consider the following CTE as the sequence table:
WITH seq AS (
SELECT 1 AS qty UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4
-- and so on, as many quantity values are needed
)
SELECT
ROW_NUMBER() OVER (ORDER BY c.CardID) AS ShuffID,
1 AS RoundID,
c.CardID
FROM crdCard c
INNER JOIN seq s
ON s.qty <= c.Qty
ORDER BY
c.CardID;
Upvotes: 3