2016-05-12 168 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注入安全并比较结果。

相关问题