Ранжирование строк с нелинейным порядком

Мне нужно ранжировать эти строки:

Тип Имя Счет Собака Тедди 50 Собака Макс 10 Собака Рокки 70 Кот Зои 45 Собака Приятель 20 Собака Дейзи 30 Собака герцог 20

Именно таким образом:

Тип Имя Счет Классифицировать Собака Рокки 70 1 Собака Тедди 50 2 Кот Зои 45 3 Собака Дейзи 30 3 Собака Приятель 20 4 Собака герцог 20 4 Собака Макс 10 6

Без типа Cat это обычная RANK() функция SQL.

«Кошка» в рейтинге не должна отнимать позиции у других собак. Тип «Кошка» должен иметь тот же ранг, что и следующий тип «Собака», независимо от очков.

Функциональность RANK() необходима для всех типов «собак» (в примере Бадди и Дюк — 4-е, а Макс — 6-е).

Возможно создание временной таблицы/хранимой процедуры и дальнейшая обработка результатов... но я хотел бы знать, есть ли более простой способ сделать это.

Будет здорово увидеть, что вы попробовали.

Dale K 15.03.2024 08:33

Временная таблица вам точно не понадобится. Если вы предоставляете DDL+DML, вам будет намного проще помогать людям.

Dale K 15.03.2024 08:36

@DaleK Вы правы, но я использовал только функцию RANK()... У меня заканчиваются идеи XD

Samuel 15.03.2024 09:18
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
3
157
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Отрегулируйте оценку кошки так, чтобы она соответствовала следующей оценке собаки, а затем ранжируйте ее. (Или плотный ранг... желаемые результаты в нынешнем виде тоже не совпадают).

WITH cte AS (
    SELECT
        Type,
        Name,
        Score,
        MAX(CASE WHEN Type = 'Dog' THEN Score END) OVER (ORDER BY Score ASC) NewScore
    FROM YourTable
)
SELECT Type, Name, Score,
  DENSE_RANK() OVER (ORDER BY NewScore DESC) DenseRank,
  RANK() OVER (ORDER BY NewScore DESC) Rank
FROM cte
ORDER BY Score DESC;

Возврат:

Тип Имя Счет ПлотныйРанк Классифицировать Собака Рокки 70 1 1 Собака Тедди 50 2 2 Кот Тед 46 3 3 Собака Дейзи 30 3 3 Собака Приятель 20 4 6 Собака герцог 20 4 6 Собака Макс 10 5 8

О, я, возможно, неправильно понял... исходя из желаемых результатов, возможно, вы хотите сначала ранжировать собак, а затем просто присоединиться к кошкам... в этом случае это то, что вам нужно.

WITH cte AS (
    SELECT
        Type,
        Name,
        Score,
        CASE WHEN Type = 'Dog' THEN RANK() OVER (PARTITION BY CASE WHEN Type = 'Dog' THEN 1 END ORDER BY Score DESC) END DogRank
    FROM YourTable
)
SELECT Type, Name, Score,
    MIN(DogRank) OVER (ORDER BY Score ASC) Rank
FROM cte
ORDER BY Score DESC;

Возврат:

Тип Имя Счет Классифицировать Собака Рокки 70 1 Собака Тедди 50 2 Кот Тед 46 3 Собака Дейзи 30 3 Собака герцог 20 4 Собака Приятель 20 4 Собака Макс 10 6

DBFiddle

Это разумно использовать MAX, чтобы объединить их вместе!

siggemannen 15.03.2024 09:14

Возможным решением является сочетание:

  • RANK() с соответствующим разделом (чтобы ранжировать только те строки, где Type находится Dog) и правильным предложением ORDER BY.
  • LEAD() с IGNORE NULLS (введено в SQL Server 2022).

Обратите внимание: если вы хотите получить рейтинг без пробелов в значениях рейтинга, вы можете использовать DENSE_RANK() вместо RANK().

Пример данных испытаний:

SELECT *
INTO Data
FROM (VALUES  
   ('Dog', 'Teddy', 50),
   ('Cat', 'Mary', 1),
   ('Cat', 'Ana', 70),
   ('Dog', 'Max', 10),
   ('Dog', 'Rocky', 70),
   ('Cat', 'Zoe', 45),
   ('Cat', 'Nelly', 40),
   ('Dog', 'Buddy', 20),
   ('Dog', 'Daisy', 30),
   ('Dog', 'Duke', 20)
) v (Type, Name, Score)  

Т-SQL:

SELECT
   Type, Name, Score, DogRank,
   Rank = COALESCE(
      DogRank, 
      LEAD(DogRank) IGNORE NULLS OVER (ORDER BY Score DESC, DogRank),
      COUNT(*) OVER ()
      -- or MAX(DogRank) OVER () + 1 
   )
FROM (  
   SELECT 
      *,
      DogRank = CASE WHEN Type = 'Dog' THEN RANK() OVER (PARTITION BY CASE WHEN Type = 'Dog' THEN 1 END ORDER BY Score DESC) END
   FROM Data
) t  
ORDER BY Score DESC, DogRank

Результат:

Тип Имя Счет Рейтинг собаки Классифицировать Кот Ана 70 нулевой 1 Собака Рокки 70 1 1 Собака Тедди 50 2 2 Кот Зои 45 нулевой 3 Кот Нелли 40 нулевой 3 Собака Дейзи 30 3 3 Собака герцог 20 4 4 Собака Приятель 20 4 4 Собака Макс 10 6 6 Кот Мэри 1 нулевой 10

С этим есть две проблемы... 1) Если у Зои 70 (как у Рокки), ее ранг равен 2, но он должен быть 1. 2) если у Зои 1, ее ранг равен «нулевому», а не 8.

Samuel 16.03.2024 02:08

@Сэмюэль, тебе нужно добавить все крайние случаи в образец данных. И вы объясняете, что если бы Зое было 1, то ранг был бы 8? И на самом деле, как Зоя 70 должна иметь ранг 1, а не 2, как вы сказали, кошка никогда не должна превосходить собаку по рангу.

Dale K 16.03.2024 10:22

@Сэмюэль, решение для первого краевого случая (... если у Зои 70 баллов...) - это другое предложение ORDER BY в функции LEAD(), но я не уверен, почему вам нужен ранг 8 (вместо 7) ), если у Зои 1 балл. Ответ обновляется с использованием дополнительных тестовых данных.

Zhorov 18.03.2024 10:04

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