一般的なケースで答えてください:
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
詳細な回答:
Q. SQL という文字は何の略ですか? A. 言語としての資格はほとんどありません... ROFLですが、次の重要な点を考慮してください。
CREATE TABLE MyTable
( ID INTEGER NOT NULL UNIQUE, data_col VARCHAR(10) NOT NULL );
DECLARE @MyTable TABLE
( ID INTEGER NOT NULL UNIQUE, data_col VARCHAR(10) NOT NULL );
今質問:
Q. 言語 (コンピューター サイエンス) 用語で@MyTable
、変数は変数ですか? A.そうですね...
@MyTable
問題 1:たとえば、テーブルの値を割り当てることができません
-- Assignment attempt 1:
SET @MyTable = MyTable; -- COMPILE ERROR
-- Assignment attempt 2:
SET @MyTable = ( VALUES ( 1, NULL ), ( 2, '' ), ( 3, 'Test' ) ); -- COMPILE ERROR
問題 2: 変数を比較できないなど
-- Comparison attempt 1:
IF ( @MyTable = @MyTable ) BEGIN;
PRINT 'Tables are the same.'
END; -- COMPILE ERROR
-- Comparison 2:
IF ( @MyTable = ( VALUES ( 1, NULL ), ( 2, '' ), ( 3, 'Test' ) ) ) BEGIN;
PRINT 'Tables are the same.'
END; -- COMPILE ERROR
...したがって、@MyTable は代入も比較もサポートしない「変数」であると信じなければなりません。
Q.@MyTable
が変数の場合、言語 (コンピューター サイエンス) 用語で はMyTable
何ですか? A.コンスタント?価値?タイプ?クラス?構造?上記のどれでもない?
...はい、SQL は非常に奇妙な言語です。
Q. 関係演算子とは何ですか? A. リレーショナル モデルでは、2 つのリレーション値を引数として取り、結果としてリレーション値を返す演算子です。
Q. SQL は関係演算子をサポートしていますか? A. そうではありません。SQL には、真のリレーショナル言語 ( UNION
、INTERSECT
、EXCEPT
など) のユーザーになじみのある演算子があります。ただし、SQL は非リレーショナル機能、特にヌル、重複行、重複列名をサポートしています。したがって、これらの演算子の引数と結果がリレーションと同等になるように細心の注意を払う必要があります。
Q SQL の「リレーショナル スタイル」演算子を使用して 2 つのテーブルを比較して等価性を確認する方法を教えてください。A 1 つの方法は次のとおりです。
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
上記を実証するためのテスト (以下はすべての関係値ではありませんが、演算子が SQL null で論理的に機能することを証明していることに注意してください):
例 1: テーブルは同じです (ゼロ行 == PASS を想定):
WITH tableA AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' ),
( 3, 'Test' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' ),
( 3, 'Test' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
例 2: tableB は tableB の適切なサブセットです (rows == FAIL が予想されます):
WITH tableA AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' ),
( 3, 'Test' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
例 3: tableA は tableB の適切なサブセットです (rows == FAIL が予想されます):
WITH tableA AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 3, 'Test' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' ),
( 3, 'Test' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
例 4: tableA と tableB には共通の行の値がいくつかありますが、すべてではありません (rows == FAIL が予想されます)。
WITH tableA AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 4, 'Lone' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 4, 'Sole' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
例 5: tableA と tableB には共通の行の値がありません (rows == FAIL が予想されます):
WITH tableA AS
( SELECT * FROM ( VALUES ( 5, NULL ),
( 6, 'Different' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 7, NULL ),
( 8, 'Not the same' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
Q. SQL Server DBA がこの構文を使用せず、たとえば を好む傾向があるのはなぜFULL OUTER JOIN
ですか? A. おそらく、従来の構文に精通しているなど、さまざまな理由によるものです (たとえばEXCEPT
、SQL Server 2005 で導入されました)。しかし、最も可能性が高いのは、SQL DBA は、最も効率的なクエリであると思われるものを書きたがる傾向があるということです (軽蔑的に言えば、時期尚早の最適化です)。確かに、SQL Server オプティマイザーは演算子INTERSECT
および をうまく処理できませんEXCEPT
。
Q. 「リレーショナル スタイル」の演算子が好まれるのはなぜですか? A. 冗長性が低く、間違いなく読みやすいためです。これらはどちらも、テスト コードにとって優れた品質です。