2011-01-18 108 views
4

我想在这里确定最佳方法在2008年MSSQL合并,比2008年MSSQL行,

这里是我的样本数据

TransDate Id  Active 
------------------------- 
1/18 1pm 5  1  
1/18 2pm 5  0  
1/18 3pm 5  Null  
1/18 4pm 5  1  
1/18 5pm 5  0  
1/18 6pm 5  Null 

如果ID分组,并下令由TransDate,我想最后一个非空值的活动列,并TransDate

SELECT MAX(TransDate) AS TransDate, 
     Id, 
     --LASTNonNull(Active) AS Active 

在这里,MAX是结果:

TransDate Id Active 
---------------------  
1/18 6pm 5 0 

这将是代替两个值/列就像一个凝聚但在行。

会有很多其他列,这也将有应用这个方法similiar,所以我真的不想做一个单独的加入对于每一列。

任何想法?

回答

5

我可能会使用一个相关子查询。

SELECT MAX(TransDate)    AS TransDate, 
     Id, 
     (SELECT TOP (1) Active 
     FROM T t2 
     WHERE t2.Id = t1.Id 
       AND Active IS NOT NULL 
     ORDER BY TransDate DESC) AS Active 
FROM T t1 
GROUP BY Id 

一种无需

SELECT 
    Id, 
    MAX(TransDate) AS TransDate, 
    CAST(RIGHT(MAX(CONVERT(CHAR(23),TransDate,121) + CAST(Active AS CHAR(1))),1) AS BIT) AS Active, 
    /*You can probably figure out a more efficient thing to 
    compare than the above depending on your data. e.g.*/ 
    CAST(MAX(DATEDIFF(SECOND,'19500101',TransDate) * CAST(10 AS BIGINT) + Active)%10 AS BIT) AS Active2 
FROM T 
GROUP BY Id 

或之后的意见将cross apply工作更适合您?

WITH T (TransDate, Id, Active, SomeOtherColumn) AS 
(
select GETDATE(), 5, 1, 'A' UNION ALL 
select 1+GETDATE(), 5, 0, 'B' UNION ALL 
select 2+GETDATE(), 5, null, 'C' UNION ALL 
select 3+GETDATE(), 5, 1, 'D' UNION ALL 
select 4+GETDATE(), 5, 0, 'E' UNION ALL 
select 5+GETDATE(), 5, null,'F' 

), 
T1 AS 
(
SELECT MAX(TransDate) AS TransDate, 
     Id 
FROM T 
GROUP BY Id 
) 
SELECT T1.TransDate, 
     Id, 
     CA.Active AS Active, 
     CA.SomeOtherColumn AS SomeOtherColumn 
FROM T1 
CROSS APPLY (SELECT TOP (1) Active, SomeOtherColumn 
     FROM T t2 
     WHERE t2.Id = T1.Id 
       AND Active IS NOT NULL 
     ORDER BY TransDate DESC) CA 
+0

+1了第二个选项。有趣的方法。在MAX的情况下是多余的,虽然 – RichardTheKiwi 2011-01-18 23:37:10

+0

@cyberkiwi - 好点!固定。 – 2011-01-19 00:26:37

+0

这当然有用,谢谢大家的时间和反应。我想最终我可能不得不设计表格等等。我不认为我会得到我需要的表演。这个例子中的Active列是许多列中的一列,所以我不想在设计中多达10个相关的子查询。如果我一次只能查询1个ID,那就好了。但是其中一些查询将会覆盖一系列的ID。 – 2011-01-19 14:50:47

1

这个例子应该帮助,使用分析函数MAX()OVER和ROW_NUMBER()OVER

create table tww(transdate datetime, id int, active bit) 
insert tww select GETDATE(), 5, 1 
insert tww select 1+GETDATE(), 5, 0 
insert tww select 2+GETDATE(), 5, null 
insert tww select 3+GETDATE(), 5, 1 
insert tww select 4+GETDATE(), 5, 0 
insert tww select 5+GETDATE(), 5, null 

select maxDate as Transdate, id, Active 
from (
    select *, 
     max(transdate) over (partition by id) maxDate, 
     ROW_NUMBER() over (partition by id 
       order by case when active is not null then 0 else 1 end, transdate desc) rn 
    from tww 
) x 
where rn=1 

另一种选择,相当昂贵,可能是通过XML这样做。仅用于教育目的

select 
    ID = n.c.value('@id', 'int'), 
    trandate = n.c.value('(data/transdate)[1]', 'datetime'), 
    active = n.c.value('(data/active)[1]', 'bit') 
from 
(select xml=convert(xml, 
    (select id [@id], 
     ( select * 
      from tww t 
      where t.id=tww.id 
      order by transdate desc 
      for xml path('data'), type) 
    from tww 
    group by id 
    for xml path('node'), root('root'), elements) 
)) x cross apply xml.nodes('root/node') n(c) 

它的工作原理是生成的XML将每条记录都作为ID的子节点。空列已被省略,所以使用xpath(child/columnname)找到的第一列是第一个与COALESCE相似的非空值。

0

你可以使用子查询:

SELECT MAX(TransDate) AS TransDate 
,  Id 
,  (
     SELECT TOP 1 t2.Active 
     FROM YourTable t2 
     WHERE t1.id = t2.id 
       and t2.Active is not null 
     ORDER BY 
       t2.TransDate desc 
     ) 
FROM YourTable t1 
0

我创建了一个名为#TEMP临时表来测试我的解决方案,并在这里就是我想出了:

transdate    id active 
1/1/2011 12:00:00 AM 5 1 
1/2/2011 12:00:00 AM 5 0 
1/3/2011 12:00:00 AM 5 null 
1/4/2011 12:00:00 AM 5 1 
1/5/2011 12:00:00 AM 5 0 
1/6/2011 12:00:00 AM 5 null 
1/1/2011 12:00:00 AM 6 2 
1/2/2011 12:00:00 AM 6 3 
1/3/2011 12:00:00 AM 6 null 
1/4/2011 12:00:00 AM 6 2 
1/5/2011 12:00:00 AM 6 null 

这个查询.. 。

select max(a.transdate) as transdate, a.id, (
    select top (1) b.active 
    from #temp b 
    where b.active is not null 
    and b.id = a.id 
    order by b.transdate desc 
) as active 
from #temp a 
group by a.id 

返回这些结果。

transdate    id active 
1/6/2011 12:00:00 AM 5 0 
1/5/2011 12:00:00 AM 6 2 
0

假设名为“test1”的表,如何使用ROW_NUMBER,OVER和PARTITION BY?

SELECT transdate, id, active FROM 
    (SELECT transdate, ROW_NUMBER() OVER(PARTITION BY id ORDER BY transdate desc) AS rownumber, id, active 
    FROM test1 
    WHERE active is not null) a 
WHERE a.rownumber = 1