29

すべて同じテーブルにある複数の列から一意の 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 ステートメントを記述するよりクリーンな方法はありますか?

4

4 に答える 4

32

あいまいなテキスト データではなく、質問にコードを含めることをお勧めします。これにより、全員が同じデータを操作できるようになります。私が想定したサンプルのスキーマとデータは次のとおりです。

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不要です。重複を排除しない演算子がありますが、ここでは適切ではありませんUNIONUNION 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を作成しました。

クエリ オプティマイザーは、2 つのテーブル スキャン、連結、個別の並べ替え、および選択の両方のクエリに対して、この実行計画を作成します。

SQL Server が 2 つのクエリに対して同じ実行プランを生成する場合、それらは実質的にも論理的にも同等です。

上記を質問のクエリの実行計画と比較してください。

DISTINCT 句により、SQL Server 2005 は冗長な並べ替え操作を実行します。

この句により、SQL Server 2005 は冗長な並べ替え操作を実行します。これは、クエリ オプティマイザが、最初のクエリでDISTINCTによって除外された重複が後のクエリで除外されることを認識していないためです。DISTINCTUNION

このクエリは他の 2 つのクエリと論理的に同等ですが、冗長な操作により効率が低下します。大規模なデータ セットでは、クエリが結果セットを返すのに、ここにある 2 つよりも時間がかかると予想されます。私の言葉を鵜呑みにしないでください。自分の環境で試してみてください。

于 2012-07-03T00:31:43.010 に答える
5

次のようなものを試してください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値を返します。

于 2012-07-03T00:09:26.827 に答える
0

ユニオンは、必要な行データがタイプ、値などの点で類似している場合に適用されます。結果が同じままであるため、同じテーブルまたは別のテーブルに列があるかどうかは関係ありません (既に述べた上記の回答のいずれかで)けれど)。

重複が必要ないため、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
);
于 2019-05-15T11:06:47.173 に答える
0

2 つ以上の列がある場合は、これを試してください。

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
于 2019-02-13T14:47:04.363 に答える