T-SQL语句超过子句排名函数

时间:2017-07-21 12:31:35

标签: sql sql-server tsql

我有一张看起来像这样的表:

Field1  Field2  ValidFrom
200     a       01.01.1999
200     b       01.01.2015
210     c       01.01.2015
210     c       01.01.2010

现在我尝试生成一个带有附加列的select语句,当Field1保持不变但Field2发生变化时,该列会递增。 extraColumn中值的顺序应取决于ValidFrom,这意味着例如1为01.01.1999,2为2015年1月1日(而不是相反!)。 当Field1更改时,extraColumn中的值应该再次从1开始。当Field1和Field2的组合没有变化时,它应该保持相同的值。 所以我希望得到的结果如下:

extraColumn Field1  Field2  ValidFrom
1           200     a       01.01.1999
2           200     b       01.01.2015
1           210     c       01.01.2015
1           210     c       01.01.2010

我试图通过将此查询与RANK()函数一起使用来获得此结果:

select RANK() OVER (
  PARTITION BY [Field1], [Field2] 
  ORDER BY [ValidFrom] DESC
) as 'extraColumn'
,Field1 ,Field2 ,ValidFrom
FROM table1

不幸的是,这并没有像我预期的那样起作用,它确实与我想要的相反,所以我的结果看起来像:

extraColumn Field1  Field2  ValidFrom
1           200     a       01.01.1999
1           200     b       01.01.2015
1           210     c       01.01.2015
2           210     c       01.01.2010

任何想法我做错了什么?

4 个答案:

答案 0 :(得分:2)

使用DENSE_RANK,您需要在Field2中使用order by才能获得所需的结果ValidFrom

DENSE_RANK() OVER (PARTITION BY [Field1] ORDER BY [Field2])

答案 1 :(得分:2)

Here我已经回答了类似的问题。以下是适应您的条件:

-- Preparation
declare @t table (
  Field1 int,
  Field2 char,
  ValidFrom date
);

insert into @t (Field1, Field2, ValidFrom)
values
(200, 'a', '19990101'),
(200, 'b', '20150101'),
(210, 'c', '20150101'),
(210, 'c', '20100101');

-- The query
with cte as (
  select t.*,
    lag(t.Field2) over(partition by t.Field1 order by t.ValidFrom) as [Prev2]
  from @t t
)
select c.Field1, c.Field2, c.ValidFrom,
  sum(case when c.Prev2 = c.Field2 then 0 else 1 end)
  over(partition by c.Field1 order by c.ValidFrom) as [ExtraColumn]
from cte c;

我只希望你不会对数百万或记录进行此操作,因为2分区不会让CPU和内存变得容易。哦,是的,您需要SQL Server 2012或更高版本才能实现此功能。

答案 2 :(得分:1)

尝试这样......

WITH 
    cte_MaxDate AS (
        SELECT 
            *,
            MaxDate = MAX(td.ValidFrom) OVER (PARTITION BY td.Feild1, td.Field2)
        FROM
            #TestData td
        )
SELECT 
    DENSE_RANK() OVER (PARTITION BY md.Feild1 ORDER BY md.MaxDate, md.Field2),
    md.Feild1, md.Field2, md.ValidFrom--, md.MaxDate
FROM
    cte_MaxDate md;

答案 3 :(得分:1)

我认为你必须在这里使用递归来逐行计算,无论field2是否改变。

WITH CTE_RN AS 
(
    SELECT  * 
    , ROW_NUMBER() OVER (PARTITION BY Field1 ORDER BY ValidFrom) RN
    FROM Table1
)
, RCTE AS 
(
    SELECT *, 1 AS ExtraColumn 
    FROM CTE_RN WHERE RN = 1

    UNION ALL

    SELECT c.*
    , CASE WHEN r.Field2 = c.Field2 THEN r.ExtraColumn ELSE r.ExtraColumn + 1 END
    FROM RCTE r 
    INNER JOIN CTE_RN c ON r.Field1 = c.Field1 AND r.RN + 1 = c.RN

)
SELECT * 
FROM RCTE
ORDER BY Field1, ValidFrom
OPTION (MAXRECURSION 0)

SQLFiddle DEMO (我为更复杂的样本添加了更多行)