2013-10-10 42 views
2

我已经标识下面的表格排序,年DESC如何根据列的变化值对记录进行分组/排名?

 
Id Year Valid 
1 2011 1 
1 2010 1 
1 2009 0 
1 2002 1 
4 2013 1 
4 2012 1 
4 2011 1 
etc. 

我想有像一个额外的等级字段:

 
Id Year Valid Rank 
1 2011 1  1 
1 2010 1  1 
1 2009 0  2 
1 2002 1  3 
4 2013 1  1 
4 2012 1  1 
4 2011 1  1 
etc. 

基本上每个ID交替在每一次改变行列有效的字段。以这种方式,我可以在rank = 1字段上查询每个Id的所有Valid = 1记录,直到第一个Valid = 0。或者是否有更简单的方法来选择匹配特定条件的第一个最高记录数(对于Id = 1,只有前两个记录)。我已经玩过ROW_NUMBER(),RANK()和PARTITION BY,但我似乎无法让它工作。由于实际查询是针对大型数据库运行的,因此必须避免嵌套查询。

任何任何想法?

感谢和欢呼声, 奈奎斯特

+0

您能否澄清“排名”专栏的工作原理以及如何针对您选择的这个选项进行查询。 – ImGreg

回答

1

是,使用LEFT JOIN,我们可以做到这一点。 请参阅下面的代码和结果。

第一张图像是插入的实际数据,第二张图像是预期的结果。

enter image description here

DECLARE @t TABLE 
(
    id  INT 
    ,_YEAR INT 
    ,valid TINYINT 
) 
INSERT INTO @t(id, [_YEAR], valid) 
      SELECT 1,2011,1 
UNION ALL SELECT 1,2010,1 
UNION ALL SELECT 1,2009,0 
UNION ALL SELECT 1,2002,1 
UNION ALL SELECT 4,2013,1 
UNION ALL SELECT 4,2012,1 
UNION ALL SELECT 4,2011,1 
UNION ALL SELECT 5,2013,0 
UNION ALL SELECT 5,2011,1 
UNION ALL SELECT 5,2010,1 
UNION ALL SELECT 6,2010,1 
UNION ALL SELECT 6,2011,0 
UNION ALL SELECT 6,2014,1 


SELECT q1.* 
FROM @t q1 
LEFT JOIN 
(
    SELECT id,MAX(_YEAR) ZeroYear 
    FROM @t 
    WHERE valid = 0 
    GROUP BY id 
)q2 
    ON q1.id=q2.id 
WHERE 
(q2.ID IS NULL) 
OR 
(q2.id IS NOT NULL AND q1.id IS NOT NULL AND q1.id=q2.id AND q1.[_YEAR] > q2.ZeroYear) 

编辑-1: 在该列ZeroYear上面的查询,以前我做MIN(_YEAR),但你可以从 “舍甫琴科M”,而不是最小的评论看右边的功能是MAX。

+0

工程就像一个魅力!谢谢! – Nyquist

+0

尽管OP表示,*'每个Id都达到第一个有效值= 0'*,但它们表示按照“Year DESC”的顺序排列,因此您应该使用MAX(_YEAR)而不是MIN (_YEAR)'。另外,主SELECT的WHERE子句中的一些谓词是多余的,但通常这个想法很好。 –

+0

您可以指定Where子句中的冗余条件吗?我会很感激时间。它总是很高兴学习高效的编码。是的。我看看是否有多次出现的Year With Zero查询应该选择MAX而不是Min。我已更新查询。 –

0

如果您使用SQL 2012,您可以使用lag

select id, year, valid, 
    case when ch = 0 then 1 else lag(ch,1,0) over (order by id, year desc) + 2 end rank 
from 
    (
     select 
      * , 
      abs(valid - lag(valid,1,1) over (order by id, year desc)) as ch 
     from YourTable 
    ) t 
1

这有点类似于@Anup Shah's suggestion,但不使用连接,而是使用一个窗口集合函数:

WITH derived AS (
    SELECT 
    Id, 
    Year, 
    Valid, 
    LatestInvalidYear = ISNULL(
     MAX(CASE Valid WHEN 0 THEN Year END) OVER (PARTITION BY Id), 
     0 
    ) 
    FROM atable 
) 
SELECT 
    Id, 
    Year, 
    Valid 
FROM derived 
WHERE Year > LatestInvalidYear 
; 

基本上,窗口MAX每Id计算的最新Valid = 0年。如果没有找到这样的年份,MAX会产生一个NULL值,用ISNULL替换为0。因此,对于您例如,derived组将返回此:

Id Year Valid LatestInvalidYear 
-- ---- ----- ----------------- 
1 2011 1  2009 
1 2010 1  2009 
1 2009 0  2009 
1 2002 1  2009 
4 2013 1  0 
4 2012 1  0 
4 2011 1  0 

很明显,你现在可以轻松地应用滤镜Year > LatestInvalidYear获得所需的行,这是exacly主要选择做什么。

相关问题