Есть ли функция, которая может возвращать отрицательный рейтинг для значений. Оракул

У меня есть сценарий, в котором я должен получить отрицательный рейтинг для значений ниже порогового предела в 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). – введите описание изображения здесь

Похоже, вы могли бы разделить запрос ранжирования на два, ранжируя население < 5000 и население > 5000 отдельно.

Thilo 21.01.2019 14:40
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
1
416
2

Ответы 2

Используйте комбинацию аналитических функций 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

дб <> рабочий пример здесь


Обновлять:

Настройка 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: если вам нужен уникальный ранг для каждой строки и не нужна строка с рангом 0, если нет значения 5000:

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

дб <> рабочий пример здесь

Этот запрос имеет некоторые трудности в случае, если в таблице нет строки с TARGET=5000.

Marmite Bomber 21.01.2019 22:29

Аналогично следует рассмотреть случай с более чем одной строкой с TARGET=5000.

Marmite Bomber 22.01.2019 07:59

Это достойная транскрипция вашего требования.

У вас есть три разных случая 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

Другие вопросы по теме