Это работает для 2 , но не для 3 (потому что он недостаточно умен, чтобы правильно обрабатывать остаток)
-- SO2992861
DECLARE @width AS int = 2
DECLARE @t AS TABLE (Id int, FieldName varchar(15), ColumnSpan int, [Order] int)
INSERT INTO @t
VALUES (1, 'UserName', 1, 1)
,(2, 'FirstName', 1, 3)
,(3, 'LastName', 1, 4)
,(4, 'Email Address', 2, 2)
,(5, 'DOB', 1, 5)
,(6, 'Notes', 2, 7)
,(7, 'Password', 1, 6)
,(8, 'UserID', 1, 0)
SELECT Row, FieldName, [Order]
FROM(
SELECT l.FieldName
,l.ColumnSpan
,l.[Order]
,SUM(r.ColumnSpan) AS RunningTotal
,SUM(r.ColumnSpan) / @width + CASE WHEN SUM(r.ColumnSpan) % @width <> 0 THEN 1 ELSE 0 END AS Row
FROM @t AS l
LEFT JOIN @t AS r
ON r.[Order] <= l.[Order]
GROUP BY l.FieldName, l.ColumnSpan, l.[Order]
) AS X
ORDER BY [Order]