As many others have very sensibly suggested, your first port of call should be to restructure your database so you are actually storing normalised data against your PO Numbers.
That said, something we are dealt a rubbish hand and have to play the cards we get. To answer your question exactly as it is asked, you can do the following:
If you are not on SQL Server 2016 and therefore cannot use the built in string_split function, start by creating your own:
create function [dbo].[StringSplit]
(
@str nvarchar(4000) = ' ' -- String to split.
,@delimiter as nvarchar(1) = ',' -- Delimiting value to split on.
,@num as int = null -- Which value to return.
)
returns @results table(ItemNumber int, Item nvarchar(4000))
as
begin
declare @return nvarchar(4000);
-- Handle null @str values
select @str = case when len(isnull(@str,'')) = 0 then '' else @str end;
-- Start tally table with 10 rows.
with n(n) as (select n from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n(n))
-- Select the same number of rows as characters in @str as incremental row numbers.
-- Cross joins increase exponentially to a max possible 10,000 rows to cover largest @str length.
,t(t) as (select top (select len(@str) a) row_number() over (order by (select null)) from n n1,n n2,n n3,n n4)
-- Return the position of every value that follows the specified delimiter.
,s(s) as (select 1 union all select t+1 from t where substring(@str,t,1) = @delimiter)
-- Return the start and length of every value, to use in the SUBSTRING function.
-- ISNULL/NULLIF combo handles the last value where there is no delimiter at the end of the string.
,l(s,l) as (select s,isnull(nullif(charindex(@delimiter,@str,s),0)-s,4000) from s)
insert into @results
select rn as ItemNumber
,Item
from(select row_number() over(order by s) as rn
,substring(@str,s,l) as item
from l
) a
where rn = @num
or @num is null;
return;
end
Using this function you can then create a set each for your Actual Material and Ideal Material columns, combine them to find the differences using a full join and then concatenate the results using stuff and for xml into one string value:
declare @t table(PONumber int, ActualMaterial nvarchar(50), IdealMaterial nvarchar(50));
insert into @t values (1000000,'Milk-Sugar-tea','Milk-Sugar-Coffee'),(1000001,'Milk-Water','Milk-Water-Ice-tea');
with a as
(
select t.PONumber
,a.Item
from @t t
outer apply dbo.StringSplit(t.ActualMaterial,'-',null) a
), i as
(
select t.PONumber
,i.Item
from @t t
outer apply dbo.StringSplit(t.IdealMaterial,'-',null) i
), m as
(
select isnull(a.PONumber,i.PONumber) as PONumber
,isnull(a.Item,i.Item) as Item
from a
full join i
on(a.PONumber = i.PONumber
and a.Item = i.Item
)
where a.Item is null
or i.Item is null
)
select t.PONumber
,t.ActualMaterial
,t.IdealMaterial
,stuff((select '-' + m.Item
from m
where t.PONumber = m.PONumber
order by m.Item
for xml path('')
)
,1,1,'') as Mismatch
from @t t
order by PONumber;
Output:
+----------+----------------+--------------------+------------+
| PONumber | ActualMaterial | IdealMaterial | Mismatch |
+----------+----------------+--------------------+------------+
| 1000000 | Milk-Sugar-tea | Milk-Sugar-Coffee | Coffee-tea |
| 1000001 | Milk-Water | Milk-Water-Ice-tea | Ice-tea |
+----------+----------------+--------------------+------------+