2016-05-12 101 views
0

我試圖比較兩個存儲在變量中的查詢的結果集。SQL Server:如何比較存儲在變量中的兩個查詢的結果

我已經試過如下:

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)) 

這種方法有兩個問題:if語句不喜歡EXEC語句(除UNION當你實際使用的查詢,而不是變量的所有EXCEPT結構工程)。

第二個問題是,即使使用實際查詢,兩個查詢的列順序必須相同,否則resulsets將不匹配。但是,爲了我的目的,我需要這些結果集進行匹配。我想我需要一種方式來訂購這些列,但我不確定這是否可能。

編輯: 我無法控制傳入的查詢,因爲這是一個應用程序的代碼,旨在檢查學生對教師查詢的答案查詢。我不能選擇不使用*。

+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 

它發現列與來自兩個查詢相同的名稱和比較每個查詢的結果的,返回從查詢1行不包括在查詢2和其他方式。

比方說,你有兩個查詢與結果如下:

sql query one

和另一個問題:

sql query two

正如你可以看到第二個查詢有一個附加列,列不是以相同的順序,只有一個元組在兩個查詢中。

執行上述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注入安全並比較結果。

相關問題