Hi @alhowarthWF ,
Please try the following solution.
It extends your method by covering all the columns by using XML and XQuery.
Also, it is optimized for performance.
SQL
-- DDL and sample data population, start
DECLARE @SERVERSX TABLE (csn VARCHAR(100),ms VARCHAR(200),os VARCHAR(200),rb VARCHAR(200));
INSERT INTO @SERVERSX VALUES
('server1','TeamA;TeamB','TeamX;TeamY','TeamM;TeamN'),
('server2','TeamC;TeamA','TeamZ;TeamW','TeamO;TeamP'),
('server3','TeamP;TeamX','TeamY','TeamN');
-- DDL and sample data population, end
;WITH cte AS
(
SELECT csn
, TRY_CAST('<M>' + REPLACE(ms, ';', '</M><M>') + '</M>' AS XML) AS Middle
, TRY_CAST('<M>' + REPLACE(os, ';', '</M><M>') + '</M>' AS XML) AS oss
, TRY_CAST('<M>' + REPLACE(rb, ';', '</M><M>') + '</M>' AS XML) AS rbb
FROM @ServersX
)
SELECT csn
, a.value('(./text())[1]','VARCHAR(200)') AS Middle
, b.value('(./text())[1]','VARCHAR(200)') AS os
, c.value('(./text())[1]','VARCHAR(200)') AS rb
FROM cte
CROSS APPLY Middle.nodes('/M') AS t1(a)
CROSS APPLY oss.nodes('/M') AS t2(b)
CROSS APPLY rbb.nodes('/M') AS t3(c)
ORDER BY 1,2,3,4;
Output
+---------+--------+-------+-------+
| csn | Middle | os | rb |
+---------+--------+-------+-------+
| server1 | TeamA | TeamX | TeamM |
| server1 | TeamA | TeamX | TeamN |
| server1 | TeamA | TeamY | TeamM |
| server1 | TeamA | TeamY | TeamN |
| server1 | TeamB | TeamX | TeamM |
| server1 | TeamB | TeamX | TeamN |
| server1 | TeamB | TeamY | TeamM |
| server1 | TeamB | TeamY | TeamN |
| server2 | TeamA | TeamW | TeamO |
| server2 | TeamA | TeamW | TeamP |
| server2 | TeamA | TeamZ | TeamO |
| server2 | TeamA | TeamZ | TeamP |
| server2 | TeamC | TeamW | TeamO |
| server2 | TeamC | TeamW | TeamP |
| server2 | TeamC | TeamZ | TeamO |
| server2 | TeamC | TeamZ | TeamP |
| server3 | TeamP | TeamY | TeamN |
| server3 | TeamX | TeamY | TeamN |
+---------+--------+-------+-------+