I would do something like this. You might need to edit the syntax depending on how you want to handle NULL vs empty string, and it assumes that VALUE is the same datatype for all fields.
IF OBJECT_ID('tempdb..#Test1') IS NOT NULL
BEGIN
DROP TABLE #Test1
END
CREATE TABLE #Test1
(
TestID VARCHAR(10) NOT NULL PRIMARY KEY
, Value1 VARCHAR(10) NULL
, Value2 VARCHAR(10) NULL
, Value3 VARCHAR(10) NULL
, Value4 VARCHAR(10) NULL
)
INSERT INTO #Test1
(TestID, Value1, Value2, Value3, Value4)
VALUES
('f001', 'a1', 'a2', 'a2', 'a2')
, ('f002', 'a4', 'a4', 'a4', 'a5')
, ('f003', 'a2', 'a2', 'a2', NULL)
, ('f004', 'a1', 'a1', 'a1', 'a1')
, ('f005', 'a9', NULL, NULL, NULL)
SELECT TestID, Value1, Value2, Value3, Value4 FROM #Test1
;WITH CTE_Test AS
(
SELECT TestID
, Value1 AS Value
FROM #Test1
UNION ALL
SELECT TestID
, Value2 AS Value
FROM #Test1
UNION ALL
SELECT TestID
, Value3 AS Value
FROM #Test1
UNION ALL
SELECT TestID
, Value4 AS Value
FROM #Test1
)
, CTE_TestDistinct AS
(
SELECT DISTINCT TestID, Value
FROM CTE_Test
WHERE Value IS NOT NULL
)
SELECT CTE_TestDistinct.TestID
, Issue = CASE WHEN COUNT(Value) = 1 THEN 'NoIssue'
ELSE 'MisMatch'
END
FROM CTE_TestDistinct
GROUP BY TestID
UNION ALL
SELECT TestID
, 'NoIssue'
FROM #Test1
WHERE NOT(TestID IN (SELECT C.TestID FROM CTE_TestDistinct C))
IF OBJECT_ID('tempdb..#Test1') IS NOT NULL
BEGIN
DROP TABLE #Test1
END
Another method occurred to me. Again, this makes several assumptions about the data, but returns the same answer with the same source data while being effectively a one liner.
SELECT TestID
, CASE WHEN AllHashed <> Value1RHashed THEN 'Mismatch' ELSE 'NoIssue' END
FROM (
SELECT TestID
, AllHashed = HASHBYTES('md5',(ISNULL(Value1, COALESCE(Value1, Value2, Value3, Value4, ''))
+ ISNULL(Value2, COALESCE(Value1, Value2, Value3, Value4, ''))
+ ISNULL(Value3, COALESCE(Value1, Value2, Value3, Value4, ''))
+ ISNULL(Value4,COALESCE(Value1, Value2, Value3, Value4, ''))))
, Value1RHashed = HASHBYTES('md5', REPLICATE(COALESCE(Value1, Value2, Value3, Value4, ''), 4))
FROM #Test1
) D