2016-05-12 5 views
0

変数に格納されているクエリの2つの結果セットを比較しようとしています。SQL Server:変数に格納された2つのクエリの結果を比較する方法

私は次のことを試してみた

DECLARE @sql1 varchar(8000) = 'SELECT * FROM table1' 
DECLARE @sql2 varchar(8000) = 'SELECT Col2, Col1 FROM table1' 

IF EXISTS(
(EXEC sp_executesql @sql1 
    EXCEPT 
    EXEC sp_executesql @sql2) 
    UNION ALL 
(EXEC sp_executesql @sql2 
    EXCEPT 
    EXEC sp_executesql @sql1)) 

このアプローチは、二つの問題がある:文が構造EXCEPT UNION ALL EXCEPT EXEC文を(好きではない場合は、代わりに、変数の実際のクエリを使用するときに動作しますが)。

2番目の問題は、実際のクエリを使用しても、両方のクエリの列の順序が同じでなければならないか、またはresulsetsが一致しないことです。しかし私の目的のために、私は一致させるためにそれらの結果セットが必要です。私は列を注文する方法が必要だと思うが、それが可能かどうかはわからない。

EDIT: これは、教師のクエリに対する生徒の回答クエリを確認するためのアプリケーションのコードなので、着信クエリを制御できません。私は*を使用しないことを選択することはできません。

+0

EXCEPT演算子を試してみてください。 –

+3

* '*'を使わないで*任意の列の順序に依存しないでください。サブクエリが返すカラムを明示的に指定する適切なステートメントを記述してください –

+0

変数からのクエリが同じカラムを返すことを保証できますか?列名は同じですか? –

答えて

0

あなたが達成しようとするのは、SQL Serverで行われないことです。むしろクリーンな方法は、各クエリを実行し、得られた両方のデータセットをメタデータと値ごとに値ごとに比較するコードを持つことです。

次の方法を使用することはお勧めしません。私はこのストアドプロシージャ作成テスト目的のため

IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'SP_CompareQueryResults') 
    DROP PROCEDURE SP_CompareQueryResults 
GO 

CREATE PROCEDURE SP_CompareQueryResults 
(
    @sql1 NVARCHAR(4000) 
    , @sql2 NVARCHAR(4000) 
) 
AS 
BEGIN 

DECLARE @q1 NVARCHAR(MAX) = @sql1 
, @q2 NVARCHAR(MAX) = @sql2 

IF OBJECT_ID('tempdb..##q1') IS NOT NULL 
    DROP TABLE ##q1 
IF OBJECT_ID('tempdb..##q2') IS NOT NULL 
    DROP TABLE ##q2 

SET @q1 = 'SELECT * INTO ##q1 FROM (' + @q1 + ') r' 
SET @q2 = 'SELECT * INTO ##q2 FROM (' + @q2 + ') r' 

BEGIN TRY 
    EXEC (@q1) 
    EXEC (@q2) 
END TRY 
BEGIN CATCH 
    SELECT 'One of the source queries are not valid.' 
    RETURN 
END CATCH 

DECLARE @r NVARCHAR(MAX) 

SELECT @r = COALESCE(@r + ', ', ' ') + COLUMN_NAME 
FROM (
    SELECT COLUMN_NAME 
    FROM tempdb.INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = '##q1' 
    INTERSECT 
    SELECT COLUMN_NAME 
    FROM tempdb.INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = '##q2' 
) r 

SET @r = 'SELECT 1 as SourceQuery, * FROM (SELECT ' + @r + ' FROM ##q1 EXCEPT SELECT' + @r + ' FROM ##q2) r' 
+ ' UNION ALL SELECT 2 as SourceQuery, * FROM (SELECT ' + @r + ' FROM ##q2 EXCEPT SELECT' + @r + ' FROM ##q1) r' 

BEGIN TRY 
    EXEC(@r)  
END TRY 
BEGIN CATCH 
    SELECT 'Queries have not matching metadata.' 
    RETURN 
END CATCH 

IF OBJECT_ID('tempdb..##q1') IS NOT NULL 
    DROP TABLE ##q1 
IF OBJECT_ID('tempdb..##q2') IS NOT NULL 
    DROP TABLE ##q2 
END 
GO 

をそれが両方のクエリからの同じ名前の列を検索し、クエリ結果の各々とを比較し、クエリ2に含まれていないクエリ1から行を返すと他の方法で。

あなたは次のような結果との2つのクエリがあるとしましょう:あなたは列があり、2番目のクエリは、追加の列を持って見ることができるように

sql query two

sql query one

と別のものを同じ順序ではなく、両方のクエリに1つのタプルしかありません。このような上記SP実行

EXEC SP_CompareQueryResults 
@sql1 = N' 
SELECT 1 AS ID 
, ''test'' AS Value 
, CAST(1 as BIT) AS Valid 
UNION ALL 
SELECT 2, ''test2'', 0', 
@sql2 = N' 
SELECT 1 AS ID 
, CAST(1 as BIT) AS Valid 
, ''test'' AS Value 
, ''test'' AS AnotherValue 
UNION ALL 
SELECT 2, 1, ''test2'', ''whatever''' 

はあなたの両方のクエリからタプルを一致どれを与えない:

results

両方のクエリは、同じ結果が得られた場合は、SP_CompareQueryResultsは戻りませんどの行でも一致する名前の列に対して同じ値を持つと言うことができます。両方のクエリに結果の行がない場合、同じことが起こり、偽陽性が返されます。上記の手順を必要に応じて調整できます。

SQLインジェクション可能なので、このコードを本番環境で使用しないでください。これはテストしていません。一般的に、動的SQLは避けてください(必要でない場合)。

最初に述べたように、たとえばC#コードはSQLの安全注射であり、結果を比較します。

関連する問題