قم بتحديث الرتبة في جدول MySQL
سؤال
لدي هيكل الجدول التالي لمشغل الجدول
Table Player {
Long playerID;
Long points;
Long rank;
}
على افتراض أن PlayerId والنقاط لها قيم صالحة ، هل يمكنني تحديث الرتبة لجميع اللاعبين بناءً على عدد النقاط في استعلام واحد؟ إذا كان لدى شخصين نفس عدد النقاط ، فيجب عليهما ربط الرتبة.
تحديث:
أنا أستخدم السبات باستخدام الاستعلام المقترح كاستعلام أصلي. لا يحب السبات استخدام المتغيرات ، وخاصة ":". لا أحد يعرف أي حلول؟ إما عن طريق عدم استخدام المتغيرات أو العمل حول قيود السبات في هذه الحالة باستخدام HQL؟
المحلول
أحد الخيارات هو استخدام متغير الترتيب ، مثل ما يلي:
UPDATE player
JOIN (SELECT p.playerID,
@curRank := @curRank + 1 AS rank
FROM player p
JOIN (SELECT @curRank := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
ال JOIN (SELECT @curRank := 0)
يسمح الجزء بالتهيئة المتغيرة دون الحاجة إلى منفصلة SET
يأمر.
مزيد من القراءة حول هذا الموضوع:
حالة اختبار:
CREATE TABLE player (
playerID int,
points int,
rank int
);
INSERT INTO player VALUES (1, 150, NULL);
INSERT INTO player VALUES (2, 100, NULL);
INSERT INTO player VALUES (3, 250, NULL);
INSERT INTO player VALUES (4, 200, NULL);
INSERT INTO player VALUES (5, 175, NULL);
UPDATE player
JOIN (SELECT p.playerID,
@curRank := @curRank + 1 AS rank
FROM player p
JOIN (SELECT @curRank := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
نتيجة:
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 1 | 150 | 4 |
| 2 | 100 | 5 |
+----------+--------+------+
5 rows in set (0.00 sec)
تحديث: لاحظت للتو أنك تحتاج إلى علاقات لمشاركة نفس الرتبة. هذا أمر صعب بعض الشيء ، ولكن يمكن حله بمزيد من المتغيرات:
UPDATE player
JOIN (SELECT p.playerID,
IF(@lastPoint <> p.points,
@curRank := @curRank + 1,
@curRank) AS rank,
@lastPoint := p.points
FROM player p
JOIN (SELECT @curRank := 0, @lastPoint := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
للحصول على حالة اختبار ، دعنا نضيف لاعبًا آخر برصيد 175 نقطة:
INSERT INTO player VALUES (6, 175, NULL);
نتيجة:
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 6 | 175 | 3 |
| 1 | 150 | 4 |
| 2 | 100 | 5 |
+----------+--------+------+
6 rows in set (0.00 sec)
وإذا كنت بحاجة إلى الترتيب لتخطي مكان في حالة التعادل ، فيمكنك إضافة آخر IF
حالة:
UPDATE player
JOIN (SELECT p.playerID,
IF(@lastPoint <> p.points,
@curRank := @curRank + 1,
@curRank) AS rank,
IF(@lastPoint = p.points,
@curRank := @curRank + 1,
@curRank),
@lastPoint := p.points
FROM player p
JOIN (SELECT @curRank := 0, @lastPoint := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
نتيجة:
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 6 | 175 | 3 |
| 1 | 150 | 5 |
| 2 | 100 | 6 |
+----------+--------+------+
6 rows in set (0.00 sec)
ملاحظة: يرجى النظر في أن الاستعلامات التي أقترحها يمكن تبسيطها.
نصائح أخرى
دانيال ، لديك حل لطيف للغاية. باستثناء نقطة واحدة - حالة التعادل. إذا حدث التعادل بين 3 لاعبين ، فإن هذا التحديث لا يعمل بشكل صحيح. لقد غيرت الحل الخاص بك على النحو التالي:
UPDATE player
JOIN (SELECT p.playerID,
IF(@lastPoint <> p.points,
@curRank := @curRank + @nextrank,
@curRank) AS rank,
IF(@lastPoint = p.points,
@nextrank := @nextrank + 1,
@nextrank := 1),
@lastPoint := p.points
FROM player p
JOIN (SELECT @curRank := 0, @lastPoint := 0, @nextrank := 1) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
تحرير: بيان التحديث المقدم سابقًا لم ينجح.
على الرغم من أن هذا ليس بالضبط ما تطلبه: يمكنك إنشاء المرتبة أثناء الطيران عند الاختيار:
select p1.playerID, p1.points, (1 + (
select count(playerID)
from Player p2
where p2.points > p1.points
)) as rank
from Player p1
order by points desc
تحرير: محاولة بيان التحديث مرة أخرى. ماذا عن طاولة مؤقتة:
create temporary table PlayerRank
as select p1.playerID, (1 + (select count(playerID)
from Player p2
where p2.points > p1.points
)) as rank
from Player p1;
update Player p set rank = (select rank from PlayerRank r
where r.playerID = p.playerID);
drop table PlayerRank;
أتمنى أن يساعدك هذا.
وفق قواعد التطبيع, ، يجب تقييم الرتبة في وقت محدد.