SQL根据共享列有条件地选择一行或两行

SQL根据共享列有条件地选择一行或两行,sql,sql-server,Sql,Sql Server,我有尝试通过测试的设备。当他们这样做时,我会在设备的数据库中插入一个insert、test、pass或fail以及一个时间戳。我想要的是选择所有通过并失败,但如果已经通过,我不希望失败。如果一次测试多次失败,但没有通过,我只想要最近的一次失败 两个例子。该表共有4行: 设备测试通过时间戳 当它通过时,我只想选择X,我不想失败,因为它现在已经通过了。对于Y,我想要最近的失败。我希望能朝着正确的方向轻推一下。这是一个带有扭曲的优先级查询,可以使用窗口函数或union all实现。让我们来看第二种方法

我有尝试通过测试的设备。当他们这样做时,我会在设备的数据库中插入一个insert、test、pass或fail以及一个时间戳。我想要的是选择所有通过并失败,但如果已经通过,我不希望失败。如果一次测试多次失败,但没有通过,我只想要最近的一次失败

两个例子。该表共有4行:

设备测试通过时间戳


当它通过时,我只想选择X,我不想失败,因为它现在已经通过了。对于Y,我想要最近的失败。我希望能朝着正确的方向轻推一下。

这是一个带有扭曲的优先级查询,可以使用窗口函数或union all实现。让我们来看第二种方法:

select t.*
from t
where t.pass = 1
union all
(select top (1) with ties t.*
 from t
 where t.pass = 0 and
       not exists (select 1 from t t2 where t2.device = t.device and t2.test = t.test and t2.pass = 1)
 order by device, test, row_number() over (order by timestamp desc)
)
或者,更简单地说:

select t.*
from (select t.*,
             rank() over (partition by by device, test
                          order by pass desc,
                                   (case when pass = 0 then timestamp end) desc
                         ) as seqnum
      from t
     ) t
where seqnum = 1;

排名的目的是,所有通行证都是第一位的,如果存在,排名值为1。如果没有,则只有最近一次失败的排名为1。

联合所有方法的一种变体,使用CTE,通过假定合理的数据集大小的单独分组和过滤来提高可读性

;with LatestPassingTests as
(
    select  
        Device,
        Test,
        Pass,
        max([Timestamp]) as 'Timestamp'
    from t                
    where Pass = 1
    group by Device, Test, Pass
),
DeduplicatedTestResults
as
(
    select 
        Device,
        Test,
        Pass,
        [Timestamp]
    from LatestPassingTests        
    union all
    select  
        t.Device,
        t.Test,
        t.Pass,
        max(t.[Timestamp]) as 'Timestamp'
    from @tempstuff as t
        left outer join LatestPassingTests as p on (t.Device = p.Device)
    where p.Device is null
    group by t.Device, t.Test, t.Pass
)
select  
    Device,
    Test,
    Pass,
    [Timestamp] 
from DeduplicatedTestResults

如果在同一设备和测试中通过测试后不存在失败的可能性,只需使用一个简单的内部查询,最大时间为:

select Device, Test, Pass, TimeStamp from table 
join (
select Device, Test, max(Timstamp) as TimeStamp from table group by 1,2 ) t1
on t1.Device=table.Device and t1.Test=table.Test and t1.TimeStamp =table.TimeStamp
如果在同一设备和测试中通过后可能失败,并且您只需要通过,则需要2个内部连接:

select Device, Test, Pass, TimeStamp from table join (
select Device, Test, Pass, max(TimeStamp) as TimeStamp from table 
join (
select Device, Test, max(Pass) as Pass from table group by 1,2 ) t1
on t1.Device=table.Device and t1.Test=table.Test and t1.Pass =table.Pass
group by 1,2,3 ) t2
on t2.Device=table.Device and t2.Test=table.Test and t2.Pass =table.Pass and t2.TimeStamp =table.TimeStamp

到目前为止你尝试了什么?@mucio是一个完全独立的联合,带有一个where子句,不能引用我的表别名。一堆不起作用的东西。这就是union all,第二个select是否应该别名为t2?在从t2中选择1时,我得到t是无效对象。在SQL server中。试图用交叉连接替换。@ScottClark。除了拼写错误之外,这个查询是按照我的意愿编写的。这对我帮助很大。对秩函数的一个很好的介绍。非常感谢。
select Device, Test, Pass, TimeStamp from table join (
select Device, Test, Pass, max(TimeStamp) as TimeStamp from table 
join (
select Device, Test, max(Pass) as Pass from table group by 1,2 ) t1
on t1.Device=table.Device and t1.Test=table.Test and t1.Pass =table.Pass
group by 1,2,3 ) t2
on t2.Device=table.Device and t2.Test=table.Test and t2.Pass =table.Pass and t2.TimeStamp =table.TimeStamp