2013-09-26 79 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