2013-09-26 42 views
1

我已经搜索了一段时间,但只是不知道是否有一个“银弹”解决方案,我正在寻找做什么。我在我的数据库中有一张表(为了讨论的缘故,实际的列是不相关的)。我希望能够从同一个表格中查看2行,并获得2列之间不同的列表。我知道我可以编写一大堆TSQL来使这发生在特定表格中,但我希望SQL Server中有内置的函数(我正在运行2008 R2)可以做到这一点。比较MS SQL中的2行并得到不同的列

我知道像CHECKSUM这样的简单函数会告诉我,如果2行不同,但我需要具体哪些列是不同的。

最好我想使它成为一个UDF并传递表名和我想要比较的2行的主键。

任何想法或建议?

- 编辑 - 这是我想出了解决方案:

Well, It is certainly not the most elegant solution...but it will work in a pinch. 

    CREATE PROCEDURE sp_Compare_Table_Rows 
    (
     @TablePK varchar(1000), -- The Name of the Primary Key in that Table 
     @TableName varchar(1000), -- The Name of the Table 
     @PK1 int, -- The ID of the 1st table 
     @PK2 int -- The ID of the 2nd table 
    ) 
    AS 
    DECLARE @Holder table 
    (
     Column_Name varchar(250), 
     Different bit 
    ) 
    INSERT INTO @Holder(Column_Name,Different) 
    select 
    COLUMN_NAME,0 
    from 
    LPS_DEV.INFORMATION_SCHEMA.COLUMNS 
    WHERE 
    TABLE_NAME = @TableName 
    and ORDINAL_POSITION >1 

    DECLARE @LoopedColumnName varchar(250) 
    DECLARE @DynamicQuery nvarchar(max) 
    DECLARE @ORD1 int 
    DECLARE @ORD2 int 

    SET @DynamicQuery = '' 
    SET @LoopedColumnName = '' 
    SET @ORD1 = 0 
    SET @ORD2 = 0 

    DECLARE MYCUR CURSOR FOR SELECT Column_Name FROM @Holder 
    OPEN MYCUR 
    FETCH NEXT FROM MYCUR INTO @LoopedColumnName 
    WHILE @@FETCH_STATUS = 0 
     BEGIN 
      SET @DynamicQuery = 'SELECT @Outer= CHECKSUM(' + @LoopedColumnName + ') FROM ' + @TableName + ' WHERE ' + @TablePK + ' = ' + CONVERT(varchar(100),@PK1) 
      exec sp_executesql @DynamicQuery, N'@Outer int output',@ORD1 out 

      SET @DynamicQuery = 'SELECT @Outer= CHECKSUM(' + @LoopedColumnName + ') FROM ' + @TableName + ' WHERE ' + @TablePK + ' = ' + CONVERT(varchar(100),@PK2) 
      exec sp_executesql @DynamicQuery, N'@Outer int output',@ORD2 out 

      IF @ORD1 <> @ORD2 
      BEGIN 
       UPDATE @Holder SET Different = 1 WHERE Column_Name = @LoopedColumnName 
      END  
      FETCH NEXT FROM MYCUR INTO @LoopedColumnName  
     END 
    CLOSE MYCUR 
    DEALLOCATE MYCUR 

    select * from @Holder 
+0

你绝对不会是能够做到这一点的UDF。它需要动态SQL来处理传入的表名。 –

+0

Good Point Martin,我现在正在对一个解决方案进行原型设计,以确定它是否可行,它将涉及表变量和光标,我可以告诉你;) –

+0

我认为你可以用CLR UDF来做到这一点。 –

回答

0

约翰,你可以使用这样的事情。这将显示列名 - 设置@tablename和@whereclause。

declare @tablename varchar(1000), 
@cols varchar(max), 
@sqlstmt nvarchar(max), 
@whereclause nvarchar(max); 
    set @tablename = 'sometable'; 
    set @whereclause = ' where 
     a.col1 = ''SOMEOTHERVALUE'' and a.datecol2 = ''19910101'' and 
     b.col2 = ''SOMEVALUE'' and b.datecol2 = ''19910101'' 
    ' 
    select @cols = stuff((
     select ', case when a.' + c.name + ' = b.' + c.name 
      + ' then '''' else ''' + c.name + ''' end' 
      from sys.columns c 
      inner join sys.tables t on c.object_id = t.object_id 
      where t.name = @tablename 
      for xml path ('')), 1, 1, '') 

    set @sqlstmt = 'select ' + @cols + ' from ' + @tablename 
        + ' a, ' + @tablename + ' b ' + @whereclause 
    exec sp_executesql @sqlstmt 
+0

非常感谢,但我希望能够一般地工作,而不必知道要比较的列的名称。我最终在原始文章的编辑部分写了一些内容,这些文章展示了我是如何完成这项工作的。 –

+0

这是正确的约翰。由于您在存储的proc参数中使用PK col和values来选择2个唯一行,因此在上述SQL中更改@whereclause以反映相同 –

0

我做了斯利拉姆回答了一些改进,这里是新的脚本:

declare @tablename nvarchar(MAX), 
@cols varchar(max) = '', 
@sqlstmt nvarchar(max) = 'DECLARE @T AS TABLE (ColumnName NVARCHAR(MAX), Value NVARCHAR(MAX), Value2 NVARCHAR(MAX))', 
@whereclause nvarchar(max) = ''; 

set @tablename = 'TABLE_NAME'; 
set @whereclause = ' where a.FIRST_ROW_ID = ''NUMBER'' and b.SECOND_ROW_ID = ''NUMBER''' 

select @cols = (
    select ' INSERT INTO @T SELECT ''' + c.name + ''', cast(a.' + c.name + ' as nvarchar(max)), cast(b.' + c.name + ' as nvarchar(max)) from ' + @tablename + ' a, ' + @tablename + ' b ' + @whereclause + ' AND cast(a.' + c.name + ' as nvarchar(max)) != cast(b.' + c.name + ' as nvarchar(max))' 
      from sys.columns c 
      inner join sys.tables t on c.object_id = t.object_id 
      where t.name = @tablename 
      for xml path ('')) 

set @sqlstmt += @cols + ' SELECT * FROM @T' 

exec sp_executesql @sqlstmt 

你需要与你的表来代替“TABLE_NAME”,改变where子句变量。

其结果将是这样的:

ColumnName | Value | Value2 
---------------------------- 
Id   | 1  | 2 
Name  | Name 1 | Name 2