You appear to be recycling the records from each group (ID) to ensure that all IDs have the same number of records. So firstly you need to know how many of each you are going to need:
declare @maxrows int = (SELECT MAX(C) FROM (SELECT ID, COUNT(*) AS C FROM Demo GROUP BY ID) AS X)
. Use a temporary file to generate "extra" rows e.g. (there are probably better ways to do this)
select * INTO #temp from Demo
declare @continue bit = 1
WHILE @continue = 1
BEGIN
IF (SELECT MAX(C) FROM (SELECT ID, COUNT(*) AS C FROM #temp GROUP BY ID) AS X WHERE C < @maxrows) < @maxrows
INSERT INTO #temp select * from #Demo
ELSE
SET @continue = 0
END
Now you can query the temporary table assigning a row number within each ID group and get the effect you want by choosing the ORDER BY carefully...
;with cte AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID) AS rn, *
FROM #temp
)
SELECT ID, NAMES, DATEUSED
FROM cte
WHERE rn <= @maxrows
ORDER BY rn, ID
which give results
ID NAMES DATEUSED
1 A NULL
2 D NULL
3 G NULL
1 B NULL
2 E NULL
3 H NULL
1 C NULL
2 F NULL
3 I NULL
1 A NULL
2 D NULL
3 J NULL
1 B NULL
2 E NULL
3 K NULL
Point to note: Notice the semi-colon
;
when declaring the CTE. You will need that to avoid error
Msg 319, Level 15, State 1, Line 30
Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.
You could put the semicolon at the end of the previous statement but if you add any code after that and before the CTE you will get the error again. So it's best practice to put the semicolon right tight up against the CTE - as I have here.