根据级联条件有条件地从组中选择前1

时间:2014-03-13 20:33:00

标签: sql sql-server tsql

我需要根据“级联if条件”的设置从每组项目中选择“前1”记录。

分组基于MovieId,Formatid和Date。

这是我的表的一个例子(稍微分解一下,以突出我试图实现的逻辑的4个“案例”)...

Id | MovieId | FormatId | SourceId | Date       | Lock | Created    | Modified
------------------------------------------------------------------------------
1  | 1       | 1        | 1        | 2014-03-12 | 1    | 2014-03-12 | NULL
2  | 1       | 1        | 2        | 2014-03-12 | NULL | 2014-03-12 | NULL
3  | 1       | 1        | 3        | 2014-03-12 | NULL | 2014-03-12 | 2014-03-13
4  | 1       | 1        | 4        | 2014-03-12 | NULL | 2014-03-12 | NULL

5  | 1       | 2        | 1        | 2014-03-12 | NULL | 2014-03-12 | NULL
6  | 1       | 2        | 2        | 2014-03-12 | NULL | 2014-03-12 | NULL
7  | 1       | 2        | 3        | 2014-03-12 | NULL | 2014-03-12 | NULL
8  | 1       | 2        | 4        | 2014-03-12 | NULL | 2014-03-12 | NULL

9  | 1       | 3        | 1        | 2014-03-12 | NULL | 2014-03-12 | NULL
10 | 1       | 3        | 3        | 2014-03-12 | NULL | 2014-03-12 | 2014-03-13

11 | 2       | 1        | 2        | 2014-03-12 | NULL | 2014-03-12 | NULL

我的预期结果将是这些行...

1  | 1       | 1        | 1        | 2014-03-12 | 1    | 2014-03-12 | NULL
8  | 1       | 2        | 4        | 2014-03-12 | NULL | 2014-03-12 | NULL
10 | 1       | 3        | 3        | 2014-03-12 | NULL | 2014-03-12 | 2014-03-13
11 | 2       | 1        | 2        | 2014-03-12 | NULL | 2014-03-12 | NULL

所以这是算法(同样,每个MovieId / FormatId / Date组)......

首先,如果有一个SourceId = 1 AND Lock NOT NULL的记录,那么选择那个 其次,如果有一个SourceId = 4的记录,那么选择那个 第三,如果有记录,其中SourceId<> 2,然后选择最近更新的一个 最后,如果只有1个记录,其中SourceId = 2,那么选择那个。

另外两个注释/请求... 1)我已经有一个索引视图执行其中一些并使用带有ROW_NUMBER()的“条件ORDER BY”子句,即

  

ORDER BY(X结束时的情况)DESC,(然后结束时的情况)......

但这并不完全正确,而且表现可怕! 2)这个表非常大(目前大约有600万行),所以我见过的一些东西推荐用于小型表,但这个表不是其中之一。

提前致谢! - 亨利·

1 个答案:

答案 0 :(得分:0)

您的问题只是说:"使用row_number(),使用row_number()!"

这会为组中的每一行分配一个序号。行根据order by排序。为此,只需使用逻辑优先:

select Id, MovieId, FormatId, SourceId, Date, Lock, Created, Modified
from (select t.*,
             row_number() over (partition by MovieId, FormatId, Date
                                order by (case when SourceId = 1 AND Lock NOT NULL then 1
                                               when SourceId = 4 then 2
                                               when SourceId <> 2 then 3
                                               when SourceId = 2 then 4
                                               else 5
                                          end), Modified desc
                               ) as seqnum,
            sum(case when SourceId = 2 then 1 else 0 end) over (partition by MovieId, FormatId, Date) as NumSourceId2
      from table t
     ) t
where seqnum = 1 and not (SourceId = 2 and NumSourceId2 > 1);

请注意,如果不满足任何条件,这仍将选择一行。在这种情况下,你没有具体说明该做什么。