Dynamically select distinct current and previous columns from a sql table

后端 未结 2 1011
盖世英雄少女心
盖世英雄少女心 2021-01-14 12:00

I have a temporary table like so

   Id  |Name    |Status |   Rate |  Method  |ModifiedTime             |ModifiedBy
------------------------------------------         


        
相关标签:
2条回答
  • 2021-01-14 12:36

    Ok, I adapted my previous answer but on Dynamic SQL. It's a little crazy but it works (using testTable as table name you can change that just replace 'testTable'):

    DECLARE @query NVARCHAR(max) 
    
    SET @query = 'select item, case item'; 
    
    SELECT @query = @query + Stuff(( SELECT 
    ' when '''+a.NAME+''' then cast(prev'+a.NAME+' as varchar) ' 
    FROM sys.all_columns a JOIN sys.tables t ON 
    t.object_id = a.object_id AND t.NAME = 'testTable' AND a.NAME 
    NOT IN ('id', 
    'Name', 'ModifiedTime', 'ModifiedBy') FOR xml path('') ), 1, 0, 
    ''); 
    
    SET @query = @query + ' end as Before, case item '; 
    
    SELECT @query = @query + Stuff(( SELECT 
                           ' when '''+a.NAME+''' then cast('+a.NAME+' as varchar) ' 
                           FROM sys.all_columns a JOIN sys.tables t ON t.object_id = 
                           a.object_id AND t.NAME = 'testTable' AND a.NAME NOT IN ( 
                    'id', 
                           'Name', 
                           'ModifiedTime', 'ModifiedBy') FOR xml path('') ), 1, 1, 
                    ''); 
    
    SET @query = @query 
                 + ' end as After, ModifiedTime, ModifiedBy from ( select '; 
    
    SELECT @query = @query + Stuff(( SELECT a.NAME +', lag('+ a.NAME + 
                           ') over (partition by Name order by id) prev'+a.NAME+', ' 
                    FROM 
                           sys.all_columns a JOIN sys.tables t ON t.object_id = 
                    a.object_id 
                           AND t.NAME = 'testTable' AND a.NAME NOT IN ('id', 'Name', 
                           'ModifiedTime', 'ModifiedBy') FOR xml path('') ), 1, 0, 
                    ''); 
    
    SET @query = @query 
                 + '  ModifiedBy, ModifiedTime from testTable ) as t1 cross join  (' 
    ; 
    
    SELECT @query = @query + Stuff(( SELECT ' select '''+ a.NAME + 
                    '''as item union all ' 
                           FROM 
                           sys.all_columns a JOIN sys.tables t ON t.object_id = 
                    a.object_id 
                           AND t.NAME = 
                           'testTable' AND a.NAME NOT IN ('id', 'Name', 
                    'ModifiedTime', 
                           'ModifiedBy') FOR xml path('') ), 1, 1, ''); 
    
    SET @query = LEFT(@query, Len(@query) - 10); --get rid of last union all 
    SET @query = @query + ' ) items where '; 
    
    SELECT @query = @query + Stuff(( SELECT ' or (item = '''+ a.NAME +''' and '+ 
                    a.NAME + 
                           ' !=  prev'+ a.NAME +')' FROM sys.all_columns a JOIN 
                    sys.tables 
                           t ON t.object_id = a.object_id AND t.NAME = 'testTable' 
                    AND 
                           a.NAME NOT IN ('id', 'Name', 'ModifiedTime', 'ModifiedBy' 
                    ) FOR 
                           xml 
                           path('') ), 1, 3, ''); 
    
    SET @query = @query + ' order by ModifiedTime'; 
    
    EXECUTE Sp_executesql 
      @query 
    
    0 讨论(0)
  • 2021-01-14 12:37

    Assuming NAME (Recipe1) is a key

    Declare @Table table (Id int,Name varchar(50),Status int,Rate int,Method varchar(50),ModifiedTime DateTime,ModifiedBy varchar(50))
    Insert Into @Table values
    (1,'Recipe1',0,30,'xyz','2016-07-26 14:55:57.977','A'),
    (2,'Recipe1',0,30,'abc','2016-07-26 14:56:18.123','A'),
    (3,'Recipe1',1,30,'xyz','2016-07-26 14:57:50.180','b')
    
    Declare @XML xml
    Set @XML = (Select * from @Table for XML RAW)
    
    ;with cteBase as (
        Select ID           = r.value('@Id','int') 
              ,Name         = r.value('@Name','varchar(150)')
              ,ModifiedTime = r.value('@ModifiedTime','varchar(150)')
              ,ModifiedBy   = r.value('@ModifiedBy','varchar(150)')
              ,Item         = Attr.value('local-name(.)','varchar(max)')
              ,Value        = Attr.value('.','varchar(max)')
        From  @XML.nodes('/row') AS A(r)
        Cross Apply A.r.nodes('./@*[local-name(.)!="Id"]') AS B(Attr)
    )
    ,cteExt as (Select *,LastValue =Lag(Value) over (Partition By Name,Item Order by ModifiedTime) From cteBase)
    Select Name
          ,Item
          ,Before=LastValue
          ,After =Value
          ,ModifiedTime
          ,ModifiedBy
     From  cteExt 
     Where Value<>LastValue and LastValue is not null
       and Item not in ('ModifiedTime','ModifiedBy')
     Order By Name,ModifiedTime
    

    Returns

    Name    Item    Before  After   ModifiedTime            ModifiedBy
    Recipe1 Method  xyz     abc     2016-07-26T14:56:18.123 A
    Recipe1 Method  abc     xyz     2016-07-26T14:57:50.180 b
    Recipe1 Status  0       1       2016-07-26T14:57:50.180 b
    
    0 讨论(0)
提交回复
热议问题