是否有一个函数可以返回值的负排名。甲骨文

时间:2019-01-21 13:33:41

标签: sql oracle

我有一种情况,对于SQL中低于阈值限制的值,我必须排名负数。有人可以帮我吗?

Name    Target  Rank
John    2500    -2
Hopkins 4000    -1
Paul    5000    0
Gracia  5200    1

以上是目标表的示例。我需要分配排名,如图所示。对于值5000的人,应将其分配为“ 0”。对于资源低于5000的资源,其排名应为负值(-1,-2,-3 ...)对于资源高于5000的资源,其排名应为正值(1,2,3)。 – enter image description here

2 个答案:

答案 0 :(得分:4)

结合使用ROW_NUMBER()COUNT()分析函数:

Oracle设置

CREATE TABLE table_name ( Name, Target ) As
SELECT 'John',    2500 FROM DUAL UNION ALL
SELECT 'Hopkins', 4000 FROM DUAL UNION ALL
SELECT 'Paul',    5000 FROM DUAL UNION ALL
SELECT 'Gracia',  5200 FROM DUAL;

查询

SELECT t.*,
       ROW_NUMBER() OVER ( ORDER BY target ASC )
         - COUNT( CASE WHEN target < 5000 THEN 1 END ) OVER ()
         - 1 AS rnk
FROM   table_name t;

输出

NAME    | TARGET | RNK
:------ | -----: | --:
John    |   2500 |  -2
Hopkins |   4000 |  -1
Paul    |   5000 |   0
Gracia  |   5200 |   1

db <>提琴here


更新

Oracle设置

CREATE TABLE table_name ( Name, Target ) As
SELECT 'John',    2500 FROM DUAL UNION ALL
SELECT 'Hopkins', 4000 FROM DUAL UNION ALL
SELECT 'Bob',     5000 FROM DUAL UNION ALL
SELECT 'Smith',   5000 FROM DUAL UNION ALL
SELECT 'Paul',    5100 FROM DUAL UNION ALL
SELECT 'Janet',   5100 FROM DUAL UNION ALL
SELECT 'Gracia',  5200 FROM DUAL;

查询1 :如果您希望每行唯一的排名,并且如果值不为5000,则不希望排名为0的行:

SELECT t.*,
       ROW_NUMBER() OVER ( ORDER BY target ASC, name ASC )
         - COUNT( CASE WHEN target < 5000 THEN 1 END ) OVER ()
         - CASE WHEN target > 5000 AND COUNT( CASE WHEN target = 5000 THEN 1 END ) OVER () = 0 THEN 0 ELSE 1 END AS rnk
FROM   table_name t;

输出

NAME    | TARGET | RNK
:------ | -----: | --:
John    |   2500 |  -2
Hopkins |   4000 |  -1
Bob     |   5000 |   0
Smith   |   5000 |   1
Janet   |   5100 |   2
Paul    |   5100 |   3
Gracia  |   5200 |   4

查询2 :如果您希望具有相同目标的行具有相同的等级,并且仅具有5000个目标的行的等级为0:

SELECT name,
       target,
       DENSE_RANK() OVER ( ORDER BY target ASC )
         - COUNT( CASE WHEN target < 5000 AND rn = 1 THEN 1 END ) OVER ()
         - CASE WHEN target > 5000 AND COUNT( CASE WHEN target = 5000 AND rn = 1 THEN 1 END ) OVER () = 0 THEN 0 ELSE 1 END AS rnk
FROM   (
  SELECT t.*,
         ROW_NUMBER() OVER ( PARTITION BY target ORDER BY name ) AS rn
  FROM   table_name t
);

输出

NAME    | TARGET | RNK
:------ | -----: | --:
John    |   2500 |  -2
Hopkins |   4000 |  -1
Bob     |   5000 |   0
Smith   |   5000 |   0
Janet   |   5100 |   1
Paul    |   5100 |   1
Gracia  |   5200 |   2

db <>提琴here

答案 1 :(得分:2)

这是您的要求的重要转载。

您有三种不同情况的target,因此您设置了一个case,其中三个分支计算了RANK

您可以使用常规的RANK聚合分析功能,但从技术上讲,您必须在三种情况下PARTITION BY

select NAME, TARGET,
case when target = 5000 then 0
     when target > 5000 then RANK()
        over (partition by case when target > 5000 then 1 when target < 5000 then -1 else 0 end 
        order by target) 
     when target < 5000 then - RANK() 
        over (partition by case when target > 5000 then 1 when target < 5000 then -1 else 0 end 
        order by - target)
end as rank
from tab;

NAME        TARGET       RANK
------- ---------- ----------
John          2500         -2
Hopkins       4000         -1
Paul          5000          0
Gracia        5200          1