同じ行で異なる値を持つ識別子を見つけようとしています。
+------------+--------+--------+--------+--------+
| Identifier | Value1 | Value2 | Value3 | Value4 |
| f001 | a1 | a2 | a2 | a2 |
| f002 | a4 | a4 | a4 | a5 |
| f003 | a2 | a2 | a2 | |
| f004 | a1 | a1 | a1 | a1 |
| f002 | a9 | | | |
+------------+--------+--------+--------+--------+
例えば、
最初の識別子は「MisMatch」を返す必要があります、
2番目の識別子は「MisMatch」を返す必要があります、
3番目の識別子は「NoIssue」を返すはずです、
4番目の識別子は「不一致」を返すはずです。
5番目の識別子は「NoIssue」を返す必要があります、
どんな助けも素晴らしいだろう、私はこの時点で行き詰まっている。
数百の列がある行もあれば、1つしかない行もあります。不一致がある行を見つけられることを期待しています。
SQL Server 2008 R2を使用しています。
この質問にはExcelとSQL Serverの両方のタグが付けられています。
Excelでは ここからのアプローチ を使用できます
上記のセルF2の数式は
=IF(SUM(IF(FREQUENCY(IF(LEN(B2:E2)>0,MATCH(B2:E2,B2:E2,0),""), IF(LEN(B2:E2)>0,MATCH(B2:E2,B2:E2,0),""))>0,1))>1,"MisMatch","Match")
リンクされた記事の注記に注意してください
この例の数式は、配列数式として入力する必要があります。数式を含む各セルを選択し、 F2、次に押す CTRL+SHIFT+ENTER。
中括弧は、数式バーの数式の周りに表示されます
別の(SQL Server)方法(改善のための Geoff Patterson のクレジット)は
SELECT T.Identifier,
CASE
WHEN min_val <> max_val
THEN 'MisMatch'
ELSE 'NoIssue'
END
FROM @T T
CROSS APPLY (SELECT MIN(Val),
MAX(Val)
FROM (VALUES (Value1),
(Value2),
(Value3),
(Value4)) V(Val)) V(min_val, max_val)
言及されている「何百ものコラム」に対してうまく機能するはずです。
ただし、単純な計算スカラーと比較すると、計画がさらに複雑になります。
私はこのようなことをします。 NULLと空の文字列の処理方法によっては、構文を編集する必要がある場合があります。また、VALUEはすべてのフィールドで同じデータ型であると想定しています。
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
別の方法が私に起こりました。繰り返しになりますが、これはデータについていくつかの仮定を行いますが、実質的に1つのライナーでありながら、同じソースデータで同じ回答を返します。
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
私はCASEバリエーションに行きますが、4列はまだ大丈夫ですが、NULLのためにもう少し複雑です:
case when coalesce(Value1,Value2,Value3,Value4) = coalesce(Value2,Value3,Value4,Value1)
and coalesce(Value2,Value3,Value4,Value1) = coalesce(Value3,Value4,Value1,Value2)
and coalesce(Value3,Value4,Value1,Value2) = coalesce(Value4,Value1,Value2,Value3)
then 'NoIssue'
else 'MisMatch'
end