TSQL
WITH
source AS
(
SELECT 1 AS id,'Property X' AS columnDesc
UNION ALL SELECT 2 AS id,'Location abc'
UNION ALL SELECT 3 AS id,'error 1234'
UNION ALL SELECT 4 AS id,'error 3456'
UNION ALL SELECT 5 AS id, 'Location def'
UNION ALL SELECT 6 AS id,'error 1234'
UNION ALL SELECT 7 AS id,'error 3456'
UNION ALL SELECT 8 AS id,'Property Y'
UNION ALL SELECT 9 AS id,'Location ab'
UNION ALL SELECT 10 AS id,'error 12'
UNION ALL SELECT 11 AS id,'error 56'
UNION ALL SELECT 12 AS id,'Location de'
UNION ALL SELECT 13 AS id,'error 12'
UNION ALL SELECT 14 AS id,'error 56'
),
maxid AS
(
SELECT MAX(id) as maxid FROM source
),
properties AS
(
SELECT id, columnDesc FROM source WHERE columnDesc like 'Property%'
),
propertiesPlus AS
(
SELECT id, columnDesc,
isnull( (SELECT MIN(p2.id) FROM properties p2 WHERE p1.id < p2.id ),
(SELECT maxid FROM maxid)) as nextid
FROM properties p1
),
locations AS
(
SELECT id, columnDesc FROM source WHERE columnDesc like 'Location%'
),
locationsPlus AS
(
SELECT id, columnDesc,
isnull( (SELECT MIN(l2.id) FROM locations l2 WHERE l1.id < l2.id ),
(SELECT maxid FROM maxid)) as nextid
FROM locations l1
),
errors AS
(
SELECT id, columnDesc FROM source WHERE columnDesc like 'error%'
)
SELECT p.columnDesc as Property, l.columnDesc as Location, e.columnDesc as Error
FROM propertiesPlus p
JOIN locationsPlus l ON l.id BETWEEN p.id and p.nextid
JOIN errors e ON e.id BETWEEN l.id AND l.nextid