Как ограничить список в Python, чтобы показать N записей для каждой уникальной строки? - PullRequest
0 голосов
/ 30 мая 2018

Я пытаюсь ограничить вывод MySQL запроса, чтобы показывать только лучшие N записей для каждого жанра.Это мой код:

def selectTopNactors(n):

# Create a new connection
con=connection()

# Create a cursor on the connection
cur=con.cursor()
#execute query
int(n)
sql ="""SELECT g.genre_name, a.actor_id,COUNT(mg.genre_id) as num_mov
FROM actor as a, role as r,movie as m,genre as g, movie_has_genre as mg
WHERE a.actor_id = r.actor_id AND m.movie_id = r.movie_id
      AND m.movie_id = mg.movie_id AND g.genre_id = mg.genre_id
      AND (g.genre_id, m.movie_id) IN (SELECT g.genre_id, m.movie_id
       FROM movie as m, genre as g, movie_has_genre as mg
       WHERE m.movie_id = mg.movie_id AND mg.genre_id = g.genre_id 
       ORDER BY g.genre_id)
       GROUP BY g.genre_name, a.actor_id
       ORDER BY g.genre_name, COUNT(*) desc """

cur.execute(sql)

results = cur.fetchall()


listab = []
listac = []
for row in results:
     lista = []
     lista.append(row[0])
     lista.append(row[1])
     lista.append(row[2])
     listab = tuple(lista)
     listac.append(listab)
head = ("genreName","actorId","numberOfMovies")    
listac.insert(0,head) 


print (n)
con.commit()
return listac

И список, который возвращает это огромные (6000+) записей, поэтому я хочу показать только N записей для каждого жанра.возвращенный список здесь

1 Ответ

0 голосов
/ 30 мая 2018

В версии MySQL до 8.0 мы можем эмулировать аналитические функции, используя пользовательские переменные в тщательно обработанных запросах.Обратите внимание, что мы зависим от поведения пользовательских переменных, которое не гарантируется (задокументировано в Справочном руководстве MySQL).

SELECT @rn := IF(c.genre_name=@prev_genre,@rn+1,1) AS rn
     , @prev_genre := c.genre_name                 AS genre_name
     , c.actor_id                                  AS actor_id
     , c.num_mov                                   AS num_mov
  FROM ( SELECT @prev_genre := NULL, @rn := 0 ) i
 CROSS 
  JOIN ( SELECT g.genre_name
              , a.actor_id
              , COUNT(1) AS num_mov
           FROM actor a
           JOIN role r
             ON r.actor_id = a.actor_id
           JOIN movie m
             ON m.movie_id = r.movie_id
           JOIN movie_has_genre mg
             ON mg.movie_id = m.movie_id
           JOIN genre g
             ON g.genre_id = mg.genre_id
          GROUP
             BY g.genre_name
              , a.actor_id
          ORDER
             BY g.genre_name
              , COUNT(1) DESC
              , a.actor_id
       ) c
 ORDER
    BY c.genre_name
     , c.num_mov DESC
     , c.actor_id
HAVING rn <= 4

Литерал 4 в конце запроса представляет значение N в вопросе.

В MySQL 8.0 мы можем использовать недавно введенные аналитические функции, чтобы получить эквивалентный результат:

SELECT ROW_NUMBER() OVER(PARTITION BY c.genre_name ORDER BY c.num_mov DESC, c.actor_id)
       AS rn
     , c.genre_name                                 AS genre_name
     , c.actor_id                                   AS actor_id
     , c.num_mov                                    AS num_mov
  FROM ( SELECT g.genre_name
              , a.actor_id
              , COUNT(1) AS num_mov
           FROM actor a
           JOIN role r
             ON r.actor_id = a.actor_id
           JOIN movie m
             ON m.movie_id = r.movie_id
           JOIN movie_has_genre mg
             ON mg.movie_id = m.movie_id
           JOIN genre g
             ON g.genre_id = mg.genre_id
          GROUP
             BY g.genre_name
              , a.actor_id
          ORDER
             BY g.genre_name
              , COUNT(1) DESC
              , a.actor_id
       ) c
 ORDER
    BY c.genre_name
     , c.num_mov DESC
     , c.actor_id
HAVING rn <= 4
...