私のテーブルであるMARCには、WERKS(プラント)をキーとして200を超える列があります。
MARCのほとんどのエントリには、参照プラントからの値があります。したがって、通常、200列すべてに同じ値が含まれます。
偏差を見つけて異なる値を持つ列の名前を表示するために、参照プラント行と比較して異なる値を持つ列を見つける必要があります。
主な質問は、どの列を選択する必要があるかわからない場合の選択方法です。
上記のABASは参照プラントです。
最初の行のみが返されることを期待します。これは、その行だけが参照行と比較して差異を含んでいるためです。その行の違いは、次の列で発生します。
返される行にはこれらの4つの列のみが含まれている必要があります。
これらの3つの列がその特定のWERKSに対して異なる値を持っていることをUIに表示するために、他の列は必要ありません。
SAP HANAを使用しています。
この回答は、質問に対するコメントでMichael Greenが言及した手法の実装を示しています。 SQL Serverを使用しますが、基本的な考え方は、動的SQLをサポートするSQL互換のデータベースエンジンに適用できます。 UNPIVOT
およびPIVOT
のサポートは必要ありません。
大まかなアイデアは次のとおりです。
WERKS
ごとに1行に変換しますどの列をSELECT
にするかわからないという問題を回避するのは動的SQLの使用です-それらは動的に決定されます。
CREATE TABLE #MARC
(
c1 integer PRIMARY KEY,
c2 integer NULL,
c3 integer NULL,
c4 integer NULL,
c5 integer NULL
);
INSERT #MARC
(c1,c2,c3,c4,c5)
VALUES
(1, 2, 3, 4, 5), -- The reference row
(2, 2, 3, 4, 5),
(3, 2, 3, 4, 5),
(4, 2, 3, 7, 9), -- Differences: 7 in c4; 9 in c5
(5, 6, 3, 4, 8); -- Differences: 6 in c2; 8 in c5
-- Holds differences found (WERKS keys and column key-value pairs)
CREATE TABLE #Differences
(
c1 integer NOT NULL,
name varchar(2) NOT NULL,
value integer NOT NULL
);
WITH
Ref AS
(
-- Unpivoted reference row
SELECT
M.c1,
CA.name,
CA.value
FROM #MARC AS M
CROSS APPLY
(
VALUES
('c2', M.c2),
('c3', M.c3),
('c4', M.c4),
('c5', M.c5)
) AS CA (name, value)
WHERE
M.c1 = 1
),
NonRef AS
(
-- Unpivoted non-reference rows
SELECT
M.c1,
CA.name,
CA.value
FROM #MARC AS M
CROSS APPLY
(
VALUES
('c2', M.c2),
('c3', M.c3),
('c4', M.c4),
('c5', M.c5)
) AS CA (name, value)
WHERE
M.c1 <> 1
),
Differences AS
(
-- Find column value differences
SELECT
NonRef.c1,
NonRef.name,
NonRef.value
FROM NonRef
JOIN Ref
ON Ref.name = NonRef.name -- Same column name
AND Ref.value <> NonRef.value -- Different value
)
INSERT #Differences
(c1, name, value)
SELECT
D.c1,
D.name,
D.value
FROM Differences AS D;
-- Show differences for illustrative purposes
SELECT
D.c1,
D.name,
D.value
FROM #Differences AS D;
╔════╦══════╦═══════╗
║ c1 ║ name ║ value ║
╠════╬══════╬═══════╣
║ 4 ║ c4 ║ 7 ║
║ 4 ║ c5 ║ 9 ║
║ 5 ║ c2 ║ 6 ║
║ 5 ║ c5 ║ 8 ║
╚════╩══════╩═══════╝
-- Header
DECLARE @sql varchar(max) =
'SELECT D.c1' + CHAR(13);
-- Add aggregation
WITH D AS
(
SELECT DISTINCT D2.name
FROM #Differences AS D2
)
SELECT @sql +=
(
SELECT
', MAX(CASE WHEN D.name = ' + CHAR(39) + D.name + CHAR(39) +
' THEN D.value END) AS ' + QUOTENAME(D.name) + CHAR(13) AS [text()]
FROM D
FOR XML PATH (''), TYPE
).value('(./text())[1]', 'varchar(max)')
-- Footer
SET @sql +=
'FROM #Differences AS D' + CHAR(13) +
'GROUP BY D.c1;'
@sql
で作成されたSQLステートメントは次のとおりです。
SELECT D.c1
, MAX(CASE WHEN D.name = 'c2' THEN D.value END) AS [c2]
, MAX(CASE WHEN D.name = 'c4' THEN D.value END) AS [c4]
, MAX(CASE WHEN D.name = 'c5' THEN D.value END) AS [c5]
FROM #Differences AS D
GROUP BY D.c1;
これは手動のPIVOT
構文です。最終的な結果は、SQLを実行することによって取得されます。
EXECUTE (@sql);
╔════╦══════╦══════╦════╗
║ c1 ║ c2 ║ c4 ║ c5 ║
╠════╬══════╬══════╬════╣
║ 4 ║ NULL ║ 7 ║ 9 ║
║ 5 ║ 6 ║ NULL ║ 8 ║
╚════╩══════╩══════╩════╝
これは、必要に応じて、参照行に対する列の違いを説明する最小限の列のセットです。
-- Clean up temporary tables
DROP TABLE
#Differences,
#MARC;
上記のSQL Server固有の構文はいくつかありますが、UNPIVOT
またはAPPLY
がサポートされていない場合は、手動でLATERAL
を他の方法で実現できます。適切な単位行列テーブルへのクロス結合を使用します。動的SQLの生成では、文字列を連結する効率的な方法としてFOR XML PATH
を使用しますが、これも任意の言語で実行できます。