SQL Server比较两个应该相同的查询的结果

时间:2012-06-13 14:57:01

标签: sql-server sql-server-2005

我正在稍微修改一个sql server 2005存储过程的性能,我想快速确保旧的存储过程和新的存储过程返回完全相同的结果(列是相同的,我想确保行是相同的)。

在sql server 2005中有一种简单的方法吗?

6 个答案:

答案 0 :(得分:47)

你可以使用except结构来匹配两个查询。

select * from (select * from query1) as query1
except
select * from (select * from query2) as query2

编辑:

然后反转查询以查找与query2的差异作为驱动程序:

select * from (select * from query2) as query2
except
select * from (select * from query1) as query1

答案 1 :(得分:3)

create table #OldProcResults (
    <Blah>
)

create table #NewProcResults (
    <Blih>
)

insert into #OldProcResults
    exec MyOldProc

insert into #NewProcResults
    exec MyNewProc

然后使用Jabs的答案来比较两个表格。

答案 2 :(得分:2)

下面的存储过程将比较2个存储过程的输出结果集或2个语句。这里的关键是SP 不需要知道结果集的结构或架构,因此您可以任意测试任何SP。如果输出相同,它将返回0行。此解决方案在SQL Server中使用openrowset命令。 以下是存储过程的一些示例用法

EXEC sp_configure 'show advanced options', 1
EXEC sp_configure 'ad hoc distributed queries', 1
EXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE

SP需要以下先决条件,这可能不适合生产环境,但对本地QA,DEV和测试环境非常有用。它在代码中使用openrowset。

==================================================================================
    --== SUMMARY utlCompareStatementResults
    --==    - requires sp_configure 'show advanced options', 1
    --==    - requires sp_configure 'ad hoc distributed queries', 1
    --==    - maybe requires EXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE
    --==    - requires the RecordSet Output to have Unique ColumnNames (no duplicate columns)
    --==    - requires references in straight SQL to be fully qualified [dbname].[schema].[objects] but not within an SP
    --==    - requires references SP call to be fully qualifed [dbname].[schema].[spname] but not objects with the SP
    --== OUTPUT
    --==    Differences are returned 
    --==    If there is no recordset returned, then theres no differences
    --==    However if you are comparing 2 empty recordsets, it doesn't mean anything
    --== USAGE
    --==   DECLARE @SQL_SP1 VARCHAR(MAX)
    --==   DECLARE @SQL_SP2 VARCHAR(MAX)
    --==   -- Compare just 2 SQL Statements
    --==   SET @SQL_SP1 = 'SELECT * FROM SomeDB.dbo.Table1 WHERE CreatedOn > ''2016-05-08'''
    --==   SET @SQL_SP1 = 'SELECT * FROM SomeDB.dbo.Table1 WHERE CreatedOn > ''2016-06-11'''
    --==   EXEC utlCompareStatementResults @SQL_SP1, @SQL_SP2
    --==
    --==   -- Compare results of 2 Stored Procs
    --==   SET @SQL_SP1 = 'EXEC SomeDB.dbo.[usp_GetWithTheProgram_OLD] 100, ''SomeParamX'''
    --==   SET @SQL_SP1 = 'EXEC SomeDB.dbo.[usp_GetWithTheProgram_NEW] 50, ''SomeParamX'''
    --==   EXEC utlCompareStatementResults @SQL_SP1, @SQL_SP2
    --==================================================================================
    CREATE PROCEDURE utlCompareStatementResults
       @SQL_SP1 VARCHAR(MAX),
       @SQL_SP2 VARCHAR(MAX)
    AS
    BEGIN
        DECLARE @TABLE1 VARCHAR(200)
        DECLARE @TABLE2 VARCHAR(200)
        DECLARE @SQL_OPENROWSET VARCHAR(MAX) 
        DECLARE @CONNECTION VARCHAR(100)

        SET @CONNECTION = 'server='+@@SERVERNAME+';Trusted_Connection=yes'

        SET @SQL_SP1 = REPLACE(@SQL_SP1, '''','''''')
        SET @SQL_SP2 = REPLACE(@SQL_SP2, '''','''''')

        SET @TABLE1 = '#' + SUBSTRING(CONVERT(VARCHAR(250),NEWID()), 1, 8)
        SET @TABLE2 = '#' + SUBSTRING(CONVERT(VARCHAR(250),NEWID()), 1, 8)

        SET @SQL_OPENROWSET =
        'SELECT * ' + ' ' +
        'INTO ' + @TABLE1 + ' ' +
        'FROM OPENROWSET(''SQLNCLI'', ' + '''' + @CONNECTION + '''' +
                        ',''' + @SQL_SP1 +'''); ' +
        'SELECT * ' + ' ' +
        'INTO ' + @TABLE2 + ' ' +
        'FROM OPENROWSET(''SQLNCLI'', ' + '''' + @CONNECTION + '''' +
                        ',''' + @SQL_SP2 +'''); ' +
        '(SELECT * FROM ' + @TABLE1 + ' EXCEPT SELECT * FROM ' + @TABLE2 + ') '  +
        ' UNION ALL ' +
        '(SELECT * FROM ' + @TABLE2 + ' EXCEPT SELECT * FROM ' + @TABLE1 + '); ' +
        'DROP TABLE ' + @TABLE1 + '; ' +
        'DROP TABLE ' + @TABLE2 + '; '
        PRINT @SQL_OPENROWSET
        EXEC (@SQL_OPENROWSET)
        PRINT 'DifferenceCount: ' + CONVERT(VARCHAR(100), @@ROWCOUNT)
    END

以下是存储过程的代码。

$server = "server1"
$source_dir = "\\server2\QlikView"
$processing_dir = "M:\script_test\processing"
$processed_dir = ""
$user = 'Domain\user1'
$Password = '******'
$SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $User, $SecurePassword

 Invoke-Command -ComputerName $server -Credential $cred -ScriptBlock {
  param ($server,$source_dir,$processing_dir)
echo "$source_dir"
 Test-path $source_dir
 copy-item -Path $source_dir\* -Destination M:\script_test
  } -ArgumentList $server,$source_dir,$processing_dir

答案 3 :(得分:2)

要完成@jabs的答案,您可以使用以下模板来获取两个查询之间的区别:

WITH q1 AS (<INSERT_QUERY_1_HERE>)
   , q2 AS (<INSERT_QUERY_2_HERE>)
SELECT * FROM q1 EXCEPT SELECT * FROM q2
UNION ALL (
SELECT * FROM q2 EXCEPT SELECT * FROM q1);

示例1:由于查询相同,因此返回0行

WITH q1 AS (SELECT * FROM my_table)
   , q2 AS (SELECT * FROM my_table)
SELECT * FROM q1 EXCEPT SELECT * FROM q2
UNION ALL (
SELECT * FROM q2 EXCEPT SELECT * FROM q1);

示例2:这将返回查询之间的不同行(其中foo = 'bar'

WITH q1 AS (SELECT * FROM my_table)
   , q2 AS (SELECT * FROM my_table WHERE foo <> 'bar')
SELECT * FROM q1 EXCEPT SELECT * FROM q2
UNION ALL (
SELECT * FROM q2 EXCEPT SELECT * FROM q1);

示例3:只是为了好玩,您可以检查示例2中的查询与查询foo = 'bar'所在的行是否相同。

WITH q1 AS (

    WITH q1 AS (SELECT * FROM my_table)
       , q2 AS (SELECT * FROM my_table WHERE foo <> 'bar')
    SELECT * FROM q1 EXCEPT SELECT * FROM q2
    UNION ALL (
    SELECT * FROM q2 EXCEPT SELECT * FROM q1)

)
   , q2 AS (SELECT * FROM my_table WHERE foo = 'bar')
SELECT * FROM q1 EXCEPT SELECT * FROM q2
UNION ALL (
SELECT * FROM q2 EXCEPT SELECT * FROM q1);

答案 4 :(得分:0)

创建两个临时表,每个过程一个。 运行该过程以将行插入相应的表中。

然后从另一个MINUS select *中选择*,反之亦然

答案 5 :(得分:0)

EXCEPT是比较两个查询的关键(如@jabs所述)。

SELECT count(*), * FROM "query 1 here"
EXCEPT
SELECT count(*), * FROM "query 2 here"

为每个查询添加count(*),以确保两个查询的结果相同。万一有些重复的行被除外删除。