Reputation: 99
I have two columns
I want to output query like
I try to use loop in SQL but I failed to output query
My question is: how can I repeat the values in the [Name] column by the number in the [Total] column?
Upvotes: 0
Views: 949
Reputation: 116
For your closed question;
CREATE TABLE #Test1(
[ID] [int] NULL,
[Cnt] [varchar](50) NULL
) ON [PRIMARY]
GO
CREATE TABLE #Test2(
[ID] [int] NULL,
[col1] [varchar](50) NULL,
[col2] [varchar](50) NULL,
[col3] [varchar](50) NULL
) ON [PRIMARY]
GO
CREATE TABLE #Test3(
[ID1] [int] NULL,
Cnt int,
Id2 int,
[col1] [varchar](50) NULL,
[col2] [varchar](50) NULL,
[col3] [varchar](50) NULL
) ON [PRIMARY]
GO
INSERT INTO #TEST1 (ID, Cnt) VALUES (1, 2)
INSERT INTO #TEST1 (ID, Cnt) VALUES (2, 3)
INSERT INTO #TEST1 (ID, Cnt) VALUES (3, 1)
INSERT INTO #TEST1 (ID, Cnt) VALUES (4, 2)
INSERT INTO #TEST1 (ID, Cnt) VALUES (5, 1)
INSERT INTO #TEST1 (ID, Cnt) VALUES (6, 4)
INSERT INTO #TEST2 (ID, Col1, Col2, Col3) VALUES (1, 'a1', 'b1', 'c1')
INSERT INTO #TEST2 (ID, Col1, Col2, Col3) VALUES (2, 'a2', 'b2', 'c2')
INSERT INTO #TEST2 (ID, Col1, Col2, Col3) VALUES (3, 'a3', 'b3', 'c3')
INSERT INTO #TEST2 (ID, Col1, Col2, Col3) VALUES (4, 'a4', 'b4', 'c4')
INSERT INTO #TEST2 (ID, Col1, Col2, Col3) VALUES (5, 'a5', 'b5', 'c5')
INSERT INTO #TEST2 (ID, Col1, Col2, Col3) VALUES (6, 'a6', 'b6', 'c6')
declare @a int = 1, @b int, @c int = 0;
while @a <= (select MAX(Id) from #Test1)
begin
set @b = (select Cnt from #Test1 where ID = @a);
set @c = 0;
while @c < @b begin
insert into #Test3 (ID1, Cnt, Id2, col1, col2, col3) select @a, @b, @a, col1, col2, col3 from #Test2 where ID = @a;
set @c += 1;
end
SET @a += 1;
end
select * from #Test3 order by 1, 2;
Upvotes: 0
Reputation: 15185
This is usually handled with a recursive subquery. I derived a row order in case of duplicate names, however, that is best served using a unique key.
MS SQL Server 2017 Schema Setup:
CREATE TABLE Names(name NVARCHAR(50), total INT)
INSERT Names VALUES('ahmed',3),('mahmoud',2),('ahmed',5)
Query 1:
;WITH Normalized AS
(
SELECT *, RowNumber = ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM Names
)
,ReplicateAmount AS
(
SELECT name, running_total=total, total, RowNumber
FROM Normalized
UNION ALL
SELECT R.name, running_total=(R.running_total - 1), R.total , R.RowNumber
FROM ReplicateAmount R INNER JOIN Normalized N ON R.RowNumber = N.RowNumber
WHERE R.running_total > 1
)
SELECT
name,instance=RowNumber,total=1,OriginalTotal=total,running_total
FROM
ReplicateAmount
ORDER BY
RowNumber,name,total,running_total
OPTION (MAXRECURSION 0)
| name | instance | total | OriginalTotal | running_total |
|---------|----------|-------|---------------|---------------|
| ahmed | 1 | 1 | 3 | 1 |
| ahmed | 1 | 1 | 3 | 2 |
| ahmed | 1 | 1 | 3 | 3 |
| mahmoud | 2 | 1 | 2 | 1 |
| mahmoud | 2 | 1 | 2 | 2 |
| ahmed | 3 | 1 | 5 | 1 |
| ahmed | 3 | 1 | 5 | 2 |
| ahmed | 3 | 1 | 5 | 3 |
| ahmed | 3 | 1 | 5 | 4 |
| ahmed | 3 | 1 | 5 | 5 |
Upvotes: 3
Reputation: 454020
You can do this considerably simpler than the accepted answer.
I would suggest creating a numbers table with sequential positive integers...
CREATE TABLE dbo.Numbers(Number INT PRIMARY KEY);
INSERT INTO dbo.Numbers
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM sys.all_objects o1,
sys.all_objects o2
and then just join on number <= total
(as below)
SELECT name, 1 AS total
FROM Names nam
JOIN dbo.Numbers num ON num.Number <= nam.total;
If you are on 2017+ another method for "fun" is below (SQL Fiddle)
SELECT name, 1 AS total
FROM Names
CROSS APPLY STRING_SPLIT(SPACE(total - 1), ' ')
Upvotes: 3