web-dev-qa-db-ja.com

行の各列を比較し、それらのいずれかが異なる場合はエラーを返します

同じ行で異なる値を持つ識別子を見つけようとしています。

+------------+--------+--------+--------+--------+
| 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を使用しています。

5
John Nguyen

この質問にはExcelとSQL Serverの両方のタグが付けられています。

enter image description here

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

中括弧は、数式バーの数式の周りに表示されます

enter image description here

別の(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) 

言及されている「何百ものコラム」に対してうまく機能するはずです。

ただし、単純な計算スカラーと比較すると、計画がさらに複雑になります。

enter image description here

7
Martin Smith

私はこのようなことをします。 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
2
Jonathan Fite

私は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
0
dnoeth