すべて同じテーブルにある複数の列から一意の非null値を返す単一のSQLステートメントを作成しようとしています。
SELECT distinct tbl_data.code_1 FROM tbl_data
WHERE tbl_data.code_1 is not null
UNION
SELECT tbl_data.code_2 FROM tbl_data
WHERE tbl_data.code_2 is not null;
たとえば、tbl_dataは次のとおりです。
id code_1 code_2
--- -------- ----------
1 AB BC
2 BC
3 DE EF
4 BC
上記のテーブルでは、SQLクエリは、2つの列、つまりAB、BC、DE、EFからすべての一意の非null値を返す必要があります。
私はSQLを初めて使います。上記のステートメントは機能しますが、列が同じテーブルからのものであるため、このSQLステートメントを作成するよりクリーンな方法はありますか?
曖昧なテキストデータではなく、質問にコードを含める方がよいので、全員が同じデータを使用します。以下は、私が想定しているサンプルのスキーマとデータです。
CREATE TABLE tbl_data (
id INT NOT NULL,
code_1 CHAR(2),
code_2 CHAR(2)
);
INSERT INTO tbl_data (
id,
code_1,
code_2
)
VALUES
(1, 'AB', 'BC'),
(2, 'BC', NULL),
(3, 'DE', 'EF'),
(4, NULL, 'BC');
Blorgbeard がコメントされているように、DISTINCT
演算子は重複行を削除するため、ソリューションのUNION
句は不要です。 UNION ALL
演算子は重複を排除しませんが、ここでは適切ではありません。
DISTINCT
句を使用せずにクエリを書き換えると、この問題を解決できます。
SELECT code_1
FROM tbl_data
WHERE code_1 IS NOT NULL
UNION
SELECT code_2
FROM tbl_data
WHERE code_2 IS NOT NULL;
2つの列が同じテーブルにあるかどうかは関係ありません。列が異なるテーブルにある場合でも、ソリューションは同じです。
同じフィルター句を2回指定する冗長性が気に入らない場合は、フィルター処理する前に、ユニオンクエリを仮想テーブルにカプセル化できます。
SELECT code
FROM (
SELECT code_1
FROM tbl_data
UNION
SELECT code_2
FROM tbl_data
) AS DistinctCodes (code)
WHERE code IS NOT NULL;
2番目の構文はより見苦しいですが、論理的にはきれいです。しかし、どれがより優れたパフォーマンスを発揮しますか?
SQL Server 2005のクエリオプティマイザーが2つの異なるクエリに対して同じ実行プランを生成することを示す sqlfiddle を作成しました。
SQL Serverが2つのクエリに対して同じ実行計画を生成する場合、それらは実際上および論理的に同等です。
上記を質問のクエリの実行計画と比較します。
クエリオプティマイザーは、最初のクエリでDISTINCT
によってフィルター処理された重複が後でDISTINCT
によってフィルター処理されることを知らないため、UNION
句によってSQL Server 2005は冗長な並べ替え操作を実行します。
このクエリは論理的に他の2つと同等ですが、冗長な操作により効率が低下します。大規模なデータセットでは、クエリが結果セットを返すのに、ここの2つよりも時間がかかると予想されます。私の言葉を信じないでください。自分の環境で実験して確かめてください!
SubQuery
のようなものを試してください:
SELECT derivedtable.NewColumn
FROM
(
SELECT code_1 as NewColumn FROM tbl_data
UNION
SELECT code_2 as NewColumn FROM tbl_data
) derivedtable
WHERE derivedtable.NewColumn IS NOT NULL
UNION
は既に、結合クエリから[〜#〜] distinct [〜#〜]値を返します。
3つ以上の列がある場合はこれを試してください
CREATE TABLE #temptable (Name1 VARCHAR(25),Name2 VARCHAR(25))
INSERT INTO #temptable(Name1, Name2)
VALUES('JON', 'Harry'), ('JON', 'JON'), ('Sam','harry')
SELECT t.Name1+','+t.Name2 Names INTO #t FROM #temptable AS tSELECT DISTINCT ss.value FROM #t AS t
CROSS APPLY STRING_SPLIT(T.Names,',') AS ss
必要な行データがタイプ、値などの点で類似している場合は、ユニオンが適用されます。結果が同じままになるため、同じテーブルまたは他の列に取得する列があるかどうかは関係ありません。しかし)。
重複を望んでいないので、UNION ALLを使用しても意味がありません。また、UNIONは個別のデータを提供するため、distinctの使用は不要です。
ビューはテーブルの仮想表現であるため、ビューを作成できるのが最善の選択です。作成されたビューで変更を適切に行うことができます
Create VIEW getData AS
(SELECT distinct tbl_data.code_1
FROM tbl_data
WHERE tbl_data.code_1 is not null
UNION
SELECT tbl_data.code_2 FROM
tbl_data
WHERE tbl_data.code_2 is not null);