2012-05-25 20 views
5

我有一个Oracle查询SQL Server:如何模仿oracle保持dense_rank查询?

select max(m.id), 
     m.someId keep (DENSE_RANK FIRST ORDER BY m.UpdateDate desc) 
from MyTable m 
groupBy m.someId 

这对于像这样的数据:

id UpdateDate someId 
1 20-01-2012 10 
2 20-01-2012 10 
3 01-01-2012 10 
4 10-02-2012 20 
5 01-02-2012 20 
6 01-04-2012 30 

将返回我到底这样的:

2 10 
4 20 
6 30 

因此,对于每一个someId它会搜索最新updateDate并确实返回相应的id。 (如果最近的日期有多个ID,则需要最新的ID)。

但是对于SQL服务器,这个查询的工作方式是否一样?我的意思是这种结构keep (dense_rank first order by ..)

回答

8

我不认为你的特定查询将运行SQL Server。但是你可以达到同样的效果这样做:

SELECT id, SomeId 
FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) Corr 
     FROM MyTable) A 
WHERE Corr = 1 
+0

我不知道它..它应该如何工作,没有'someId组'?我的查询总是会返回3个条目,因为我在表中有3个不同的someIds。你的查询将返回不依赖于不同someIds数量的结果,所以它应该是错误的呢? – javagirl

+1

@javagirl - 你先试了吗?它会起作用。至于它是如何工作的,分析函数('OVER()...')可以有一个'PARTITION BY',并且不需要在整个级别上进行分组。它为表中的每一行返回一个值。 – Lamak

+0

我误解了原始数据。通过将someid放入分区而不是id来解决问题。 –

1

SQL Server不支持“保持”建设,所以你需要使用子查询:

select m.* 
from (select *, row_number() over (partition by m.someid ORDER BY m.UpdateDate desc) as seqnum 
     from MyTable m 
    ) m 
where seqnum = 1 

此发现的第一行各m.id与最新的UpdateDate。然后它在外部查询中选择该行。请注意,您不需要使用此方法进行分组。

+0

我没有得到它..它应该如何工作没有'group by someId' ?我的查询总是会返回3个条目,因为我在表中有3个不同的someIds。你的查询将返回不依赖于不同someIds数量的结果,所以它应该是错误的呢? – javagirl

+0

这不起作用,因此每个ID都会有一行,这不是我们想要的。 – Lamak

3

我返回并返回到此问题和答案。不幸的是,有几种情况下,使用“窗口函数进行排名”的迁移变得非常复杂。这两种情况是:

  1. 许多 Oracle查询的选择部分保DENSE_RANK结构基于不同的顺序进行分组套/汇总
  2. 分组

因此,我会添加到答案附加信息。 原始数据SQLFIDDLE:http://sqlfiddle.com/#!6/e5c6d/6

阅读Oracle函数:

select max(m.id), m.someId keep (DENSE_RANK FIRST ORDER BY m.UpdateDate desc) 
from MyTable m 
groupBy m.someId 

有我们的组中选择m.id的最大值(someId,UpdateDate),其中UpdateDate是它最大的组(someId )

2.直接的方式不起作用,因为错误的:列“MyTable.UpdateDate”是在选择无效列表,因为它不包含在聚合函数或GROUP BY子句中。

SELECT FIRST_VALUE(id) OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) first_in_orderedset , someId 
FROM MyTable 
GROUP BY someId 

3. improoved '直线前进' 是无效药

SELECT someId, MIN(first_in_orderedset) 
FROM 
(SELECT FIRST_VALUE(id) OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) first_in_orderedset , someId 
    FROM MyTable) t 
GROUP BY someId; 

4。交叉应用:

SELECT grouped.someId, orderedSet.FirstUpdateDate, maxInSet.first_in_orderedset FROM 
(
    SELECT mt.someId 
    FROM MyTable mt 
    GROUP BY mt.someId 
) grouped CROSS APPLY 
( 
    SELECT top 1 mt2.UpdateDate as FirstUpdateDate 
    FROM MyTable mt2 
    WHERE mt2.someId=grouped.someId 
    ORDER BY UpdateDate desc 
) orderedSet CROSS APPLY 
( 
    SELECT max(mt3.id) as first_in_orderedset 
    FROM MyTable mt3 
    WHERE mt3.someId=grouped.someId and mt3.UpdateDate=orderedSet.FirstUpdateDate 
) maxInSet; 

5.现在让我们得到更复杂的表格和更复杂的查询: ORACLE:http://sqlfiddle.com/#!4/c943c/23 SQL SERVER:http://sqlfiddle.com/#!6/dc7fb/1/0 (数据预生成的,它是在这两个沙箱是相同的 - 很容易比较的结果) 表:

CREATE TABLE AlarmReports (
    id int PRIMARY KEY, 
    clientId int, businessAreaId int , projectId int, taskId int, 
    process1Spent int, process1Lag int, process1AlarmRate varchar2(1) null, 
    process2Spent int, process2Lag int, process2AlarmRate varchar2(1) null, 
    process3Spent int, process3Lag int, process3AlarmRate varchar2(1) null 
) 

Oracle查询:

SELECT clientId, businessAreaId, projectId, 
    sum(process1Spent), 
    sum(process2Spent), 
    sum(process3Spent), 
    MIN(process1AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process1Lag DESC), 
    MIN(process2AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process2Lag DESC), 
    MIN(process3AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process3Lag DESC) 
FROM AlarmReports 
GROUP BY GROUPING SETS ((),(clientId),(clientId, projectId),(businessAreaId),(clientId,businessAreaId)) 

SQL查询:

(to be continued) 

居然还有我已经计划把用C#wroted我的自定义聚合。如果有人感兴趣,请与我联系...自定义聚合是这类问题的最佳解决方案,但它在varchar长度方面不是非常明显的。对于每个varchar长度,您都有义务创建“专用”聚合函数

0

这绝对可行。先尝试,然后争论。 当你有多个订单由你可以这样做(在Oracle做例子):

- 这一次跟上DENSE_RANK

WITH a AS (SELECT 1 s1, 4 s2, 'a' c, 10 g FROM dual UNION all 
      SELECT 2 s1, 2 s2, 'b' c, 10 g FROM dual UNION ALL 
      SELECT 3 s1, 1 s2, 'c' c, 20 g FROM dual UNION ALL 
      SELECT 4 s1, 3 s2, 'd' c, 20 g FROM dual) 
SELECT g, 
     MAX(c) KEEP (DENSE_RANK FIRST ORDER BY s1) s1, 
     MAX(c) KEEP (DENSE_RANK FIRST ORDER BY s2) s2 
    FROM a 
GROUP BY g 

- 这一个不守DENSE_RANK

WITH a AS (SELECT 1 s1, 4 s2, 'a' c, 10 g FROM dual UNION all 
       SELECT 2 s1, 2 s2, 'b' c, 10 g FROM dual UNION ALL 
       SELECT 3 s1, 1 s2, 'c' c, 20 g FROM dual UNION ALL 
       SELECT 4 s1, 3 s2, 'd' c, 20 g FROM dual) 
SELECT g, 
     MAX(DECODE(s1, 1, c)) s1, 
     MAX(DECODE(s2, 1, c)) s2 
    FROM (SELECT g,c, 
       ROW_NUMBER() OVER (PARTITION BY g ORDER BY s1) s1, 
       ROW_NUMBER() OVER (PARTITION BY g ORDER BY s2) s2 
      FROM a) b 
GROUP BY g