Z następującą tabelą MySQL:
+-----------------------------+
+ id INT UNSIGNED +
+ name VARCHAR(100) +
+-----------------------------+
Jak mogę wybrać pojedynczy wiersz ORAZ jego pozycję wśród innych wierszy w tabeli, po posortowaniu według name ASC
. Więc jeśli dane w tabeli wyglądają tak, po posortowaniu według nazwy:
+-----------------------------+
+ id | name +
+-----------------------------+
+ 5 | Alpha +
+ 7 | Beta +
+ 3 | Delta +
+ ..... +
+ 1 | Zed +
+-----------------------------+
Jak mogę wybrać Beta
wiersz pobierający bieżącą pozycję tego wiersza? Zestaw wyników, którego szukam, wyglądałby mniej więcej tak:
+-----------------------------+
+ id | position | name +
+-----------------------------+
+ 7 | 2 | Beta +
+-----------------------------+
Mogę zrobić proste, SELECT * FROM tbl ORDER BY name ASC
a następnie wyliczyć wiersze w PHP, ale ładowanie potencjalnie dużego zestawu wyników tylko dla jednego wiersza wydaje się marnotrawstwem.
sql
mysql
analytic-functions
leepowers
źródło
źródło
Odpowiedzi:
Użyj tego:
SELECT x.id, x.position, x.name FROM (SELECT t.id, t.name, @rownum := @rownum + 1 AS position FROM TABLE t JOIN (SELECT @rownum := 0) r ORDER BY t.name) x WHERE x.name = 'Beta'
... aby uzyskać unikalną wartość pozycji. To:
SELECT t.id, (SELECT COUNT(*) FROM TABLE x WHERE x.name <= t.name) AS position, t.name FROM TABLE t WHERE t.name = 'Beta'
... da krawatom tę samą wartość. IE: Jeśli na drugim miejscu znajdują się dwie wartości, obie będą miały pozycję 2, podczas gdy pierwsze zapytanie da pozycję 2 jednej z nich, a 3 drugiej ...
źródło
position
, ale jest doskonały.To jedyny sposób, jaki przychodzi mi do głowy:
SELECT `id`, (SELECT COUNT(*) FROM `table` WHERE `name` <= 'Beta') AS `position`, `name` FROM `table` WHERE `name` = 'Beta'
źródło
name <= 'Beta'
zamiast tegoposition
wartości dla krawatów.LIMIT 1
tam? W przypadku remisu otrzymujesz tylko jeden wiersz z ostatnią pozycją remisu.name
pole jest unikalne - nie ma powodu, aby zapytanie było bardziej złożone. Jeśli nie może - poczekajmy na jego oczekiwania dotyczące wyników dla remisujących nazwisk.Jeśli zapytanie jest proste, a rozmiar zwracanego zestawu wyników jest potencjalnie duży, możesz spróbować podzielić je na dwa zapytania.
Pierwsze zapytanie z zawężonymi kryteriami filtrowania tylko w celu pobrania danych z tego wiersza, a drugie zapytanie używa klauzuli
COUNT
withWHERE
do obliczenia pozycji.Na przykład w twoim przypadku
Zapytanie 1:
SELECT * FROM tbl WHERE name = 'Beta'
Zapytanie 2:
SELECT COUNT(1) FROM tbl WHERE name >= 'Beta'
Stosujemy to podejście w tabeli z rekordem 2M i jest to o wiele bardziej skalowalne niż podejście OMG Ponies.
źródło
Inne odpowiedzi wydają mi się zbyt skomplikowane.
Oto prosty przykład , powiedzmy, że masz tabelę z kolumnami:
i chcesz posortować identyfikatory użytkowników według punktów i uzyskać pozycję w wierszu („ranking” użytkownika), a następnie użyj:
SET @row_number = 0; SELECT (@row_number:=@row_number + 1) AS num, userid, points FROM ourtable ORDER BY points DESC
num
daje pozycję w wierszu (ranking).Jeśli masz MySQL 8.0+, możesz użyć ROW_NUMBER ()
źródło
Pozycja wiersza w tabeli określa, ile wierszy jest „lepszych” niż wiersz docelowy.
Więc musisz policzyć te wiersze.
WYBIERZ LICZBĘ (*) + 1 Z
table
GDZIEname
<„Beta”W przypadku remisu zwracana jest najwyższa pozycja.
Jeśli dodasz kolejny wiersz o tej samej nazwie „Beta” po istniejącym wierszu „Beta”, zwrócona pozycja będzie nadal wynosić 2, ponieważ zajmowałyby to samo miejsce w klasyfikacji.
Mam nadzieję, że pomoże to ludziom, którzy będą szukać czegoś podobnego w przyszłości, ponieważ uważam, że właściciel pytania już rozwiązał swój problem.
źródło
Mam bardzo podobny problem, dlatego nie zadam tego samego pytania, ale podzielę się tutaj, co zrobiłem, musiałem też skorzystać z grupowania i zamówienia przez AVG. Są studenci, z podpisami i innymi, i musiałem ich uszeregować (innymi słowy, najpierw obliczyłem AVG, potem zamówiłem w DESC, a na koniec musiałem dodać pozycję (ranga dla mnie), więc zrobiłem coś bardzo podobnego do najlepszej odpowiedzi tutaj, z małymi zmianami, które dostosowują się do mojego problemu):
Ostatecznie umieściłem
position
kolumnę (ranga dla mnie) w zewnętrznym SELECTSET @rank=0; SELECT @rank := @rank + 1 AS ranking, t.avg, t.name FROM(SELECT avg(students_signatures.score) as avg, students.name as name FROM alumnos_materia JOIN (SELECT @rownum := 0) r left JOIN students ON students.id=students_signatures.id_student GROUP BY students.name order by avg DESC) t
źródło
Sprawdzałem zaakceptowaną odpowiedź i wydawało mi się to trochę skomplikowane, więc tutaj jest jej uproszczona wersja.
SELECT t,COUNT(*) AS position FROM t WHERE name <= 'search string' ORDER BY name
źródło
Mam podobne problemy, w których wymagam rangi ( indeksu ) tabeli
order by votes desc
. Poniższe działa dobrze dla mnie.Select *, ROW_NUMBER() OVER(ORDER BY votes DESC) as "rank" From "category_model" where ("model_type" = ? and "category_id" = ?)
źródło
może być tym, czego potrzebujesz, z dodawaniem składni
więc użyj
SELECT * FROM tbl ORDER BY name ASC LIMIT 1
jeśli potrzebujesz tylko jednego wiersza ...
źródło