Запрос (или LINQ в Entity Framework) для получения ранга пользователя

У меня есть база данных SQL Server с таблицей с именем Users.

В этой таблице есть 2 столбца: XP (int32) и Name (nvarchar).

Мне нужен запрос SQL или Linq (это лучше, потому что я использую Entity Framework на C#), который получает Name и ранжирует всех на основе XP и отображает ранг этого имени + ранг предыдущего 1 человека + ранг следующие 1 чел.

Что-то вроде этого :

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
113
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Конечно. Попробуй это

SELECT
    XP,
    name,
    RANK() OVER (ORDER BY XP DESC) AS Ranking
FROM UserExperience;

Спасибо. Пожалуйста, помогите мне. Добавьте в него where... например where name = 'user2' просто покажите одну запись.

Yasim Yasin 30.03.2024 08:06

Бро, можешь сказать мне, как мне поступить? WHERE Ranking BETWEEN 3 AND 7 теперь работает... фактически сервер sql не видит "Рейтинг"

Yasim Yasin 30.03.2024 09:09

Вам нужно обернуть его в подзапрос

siggemannen 30.03.2024 09:10

@siggemannen Я протестировал множество режимов, думаю, что использовать этот метод «ранжирования» неправильно.

Yasim Yasin 30.03.2024 09:29

@siggemannen Я даже не могу получить ранг этого "пользователя" + ее следующих людей

Yasim Yasin 30.03.2024 09:32

@YasimYasin Думаю, что-то вроде этого задумано? WITH ranked AS (SELECT xp, name, RANK() OVER (ORDER BY XP DESC) AS ranking FROM users), ranking_compare AS (SELECT ranking FROM ranked WHERE name = 'User6') SELECT r.ranking, r.name FROM ranked r INNER JOIN ranking_compare rc ON r.ranking between rc.ranking - 1 and rc.ranking + 1 ORDER BY r.ranking, не так ли?

Jonas Metzler 30.03.2024 11:36

@JonasMetzler Я получил ответ, но и вам спасибо. Я думаю, что этот код для меня тяжелый... потому что у меня нет возможности анализировать запросы на сервере MS Sql. И я предпочитаю использовать LINQ сейчас. Вы имеете в виду, что это лучше использовать здесь «процедурный сервер Sql»?

Yasim Yasin 31.03.2024 08:47

@YasimYasin Да, на мой взгляд, здесь гораздо лучше не использовать Linq, см. мой комментарий для Charlieface под принятым вами ответом.

Jonas Metzler 31.03.2024 08:52
Ответ принят как подходящий

С точки зрения EF кажется, что это может быть просто:

var d = db.Users
  .OrderByDescending(u => u.Xp)
  .AsEnumerable()
  .Select((u, i) => new { Rank=i+1, User = u })
  .ToDictionary(at => at.Rank);

Вы выписываете всех своих пользователей из БД в порядке XP и используете перегрузку Select((user,index)=>...) для присвоения ранга (индекс + 1) и для удобства помещаем их в словарь, индексированный по рангу.

Теперь у вас есть словарь, который вы можете хранить и неоднократно просматривать, где для любого конкретного пользователя вы можете получить окружающих пользователей по рангу пользователя, которого вы уже знаете:

var user = d.Values.FirstOrDefault(u => u.User.Name == "user6");
var prev = d[user.Rank - 1];
var next = d[user.Rank + 1];

Вам нужен код, чтобы предотвратить исключение KeyNotFoundException, если вы найдете пользователя с верхним или нижним рейтингом, потому что, если вы найдете пользователя с рангом 1 по имени, вы не сможете получить пользователя с рангом 0 (их не существует). В исходном сообщении вы не сказали, что делать в этой ситуации, вы можете использовать containsKey, чтобы проверить, содержит ли словарь определенный ранг, или вы можете использовать GetValueOrDefault или TryGetValue, чтобы попытаться получить пользователя - эти методы не произойдет сбой, если пользователь не найден, но вам нужно будет решить, что делать, если он не найден

@Jonas ToDictionary не выдаст KeyNotFound. Единственное место, которое выдает ошибку, — это если найден пользователь, например, с рангом = 1, и запускается код, который пытается получить ранг = 0. Я специально предупреждаю об этом в последней строке сообщения и советую использовать TryGetValue. В ФП не указано, что делать в случае попытки получить пользователя, у которого нет пользователя с рейтингом выше или ниже него. Реализация некоторых вещей должна быть оставлена ​​на усмотрение ОП; мы не можем написать за них всю программу

flackoverstow 31.03.2024 07:55

@Charlieface, чтобы инициировать загрузку всех пользователей, потому что, хотя теоретически это может быть преобразовано, например, в ROW_NUMBER()OVER(), EF не способен переводить перегрузку Select((e,i)...), которая рассчитывает рейтинг.

flackoverstow 31.03.2024 07:58

@Charlieface Они усиленно хотят создать что-то вроде RANK или ROW_NUMBER на C# с помощью Linq. Это просто ужасно, потому что это излишне сложно, неэффективно и не для того, для чего предназначен Linq. Такую функциональность гораздо лучше реализовать на чистом SQL, где RANK и ROW_NUMBER — это встроенные функции, которые работают довольно быстро и очень просты в использовании. Да, ОП также попросил решение Linq, но честный ответ здесь будет: пожалуйста, не делайте этого, используйте чистый SQL. Проблема, с которой вам предстоит справиться, возможно KeyNotFoundException тоже это показывает.

Jonas Metzler 31.03.2024 08:07

@JonasMetzler, какая строка вызывает исключение KeyNotFound?

flackoverstow 31.03.2024 08:21

@flackoverstow После последних изменений в вашем коде (которые вы сделали после моего комментария) код работает. Спасибо за улучшение.

Jonas Metzler 31.03.2024 08:37

Добро пожаловать.. Я до сих пор не могу найти ничего, что могло бы вызвать KNF, кроме, возможно, извлечения пользователя user3, поскольку попытка получить пользователя более высокого уровня не удалась, но спасибо за подталкивание проверить это.

flackoverstow 31.03.2024 08:44

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