Sql 如何根据列的变化值对记录进行分组/排序?
我按Id订购了下表,年份描述 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. 身份证有效年份 1 2011 1 1 2010 1 1 2009 0 1 2002 1 4 2013 1 4 2012 1 4 2011 1 等 我想要的是一个额外的排名字段,如: 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. 身份证年份有效职级 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 等 基本上每个Id为有效字段中的每个更改交替排列。通过这种方式,我可以查询rank=1字段,以便在第一个Valid=0之前,每个Id都有所有Valid=1记录。或者,是否有一种更简单的方法来选择与特定条件匹配的前两条记录(对于Id=1,仅前两条记录)。我已经玩过ROW_NUMBER()、RANK()和PARTITION BY,但似乎无法让它正常工作。必须避免嵌套查询,因为实际查询是针对大型数据库运行的 有人有什么想法吗 谢谢大家,干杯,Sql 如何根据列的变化值对记录进行分组/排序?,sql,sql-server,tsql,Sql,Sql Server,Tsql,我按Id订购了下表,年份描述 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. 身份证有效年份 1 2011 1 1 2010 1 1 2009 0 1 2002 1 4 2013 1 4 2012 1 4 2011 1 等 我想要的是一
Nyquist如果您使用的是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
是的,使用左连接我们可以做到这一点。 请参阅下面的代码和结果 第一个图像是插入的实际数据,第二个图像是预期结果
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),但正如您在“Andriy M”的注释中看到的那样,MIN right函数的值是MAX。这与此类似,但不使用联接,而是使用窗口聚合函数:
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
;
基本上,窗口最大值计算每个Id
的最新Valid=0
年。如果找不到这样的年份,MAX将生成NULL,并用ISNULL替换为0。因此,对于您的示例,派生的
集将返回如下:
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>latestinvalidear
来获取所需的行,这就是主选择的功能。您能否澄清“排名”列是如何工作的,以及您将如何查询您正在进行的此选择。工作起来很有魅力!谢谢虽然OP说,“每个Id直到第一个有效值=0”,但他们的意思是按照Year DESC
的顺序,因此您可能应该使用MAX(\u Year)
而不是MIN(\u Year)
。另外,主SELECT的WHERE子句中的一些谓词是冗余的,但通常情况下,这样做很好。您可以在WHERE子句中指定冗余条件吗。我将非常感谢您抽出时间。学习高效的编码总是件好事。是的。我查看是否有多个零查询年份出现,应选择最大值而不是最小值。我已更新查询。