SQL-запрос для группировки записей и возврата их в виде списка в отношении многие-к-одному - PullRequest
0 голосов
/ 24 июня 2018

У меня возникли некоторые проблемы с использованием SQLAlchemy в полной мере в приложении Python, использующем Flask, и в понимании того, как работают отношения «один к одному» и как их можно использовать.

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

CREATE TABLE song (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(64),
artist_id INTEGER
);

CREATE TABLE artist (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(64)
);

Или, через Python SQLAlchemy, это выглядит так:

class Song(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    kws_id = db.Column(db.String(32))
    name = db.Column(db.String(255))
    artist_id = db.Column(db.Integer, db.ForeignKey('artist.id'))
    artist = db.relationship('Artist', backref='songs', foreign_keys=[artist_id])

class Artist(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))

song.artist_id относитсяв столбец artist.id;это отношения многие-к-одному, когда многие песни могут относиться к одному исполнителю.

Я надеюсь, что смогу отобразить результаты в виде:

artist:
  song1
  song2
  song3
artist2:
  song4
  song5
...

Или, в JSON, примерно: {artist: [song1, song2, song3], artist2: [song4, song5]}.(Конечная цель - вернуть это в разбивке на страницы в формате AJAX через Flask).

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

Если я хочу выполнить запрос и выбрать все песни из всехисполнителей, я могу просто запросить всех исполнителей и затем использовать атрибут backref, чтобы получить все песни.

artists = Artist.query.all()
for artist in artists:
  songs = artist.songs
  # construct json: artist => song

Однако, Я борюсь с решением для фильтрации песен, сохраняя при этомструктура данных возвращается без изменений.

Некоторые решения, которые я пробовал до сих пор:

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

artists = Artist.query.all()
for artist in artists:
  for song in artist.songs
    if song == "search": # or starts with, or something else
       # this is a song we want to match

Я мог бы построить ответ json из этого, но мне кажется, что я использую SQL как список, а не язык запросов - не использую его в полной мере и жертвуяspeed.


Я мог бы запросить таблицу исполнителей и отфильтровать по песне:

q = Artist.query
q = q.join(Artist.songs)
q = q.filter(Song.name.like("%" + search + "%"))
# q is a query which will return a list of artists
# each artist has the aforementioned backref for a list of song

Этот поиск выполняется, но возвращает всего исполнителя для каждого результата.Например, в этом наборе данных:

{artist1: [song1, song2, song3], artist2: [song4, song5, song6]}

При поиске "song1" будет возвращаться Artist1, а обратная ссылка будет содержать все песни для Artist1.Json, который я создаю, будет {artist1: [song1, song2, song3]}, а не {artist1: song1}, что было бы идеально.

Я не уверен, есть ли способ улучшить это, чтобы отфильтровать песни, которые я не хочу, или если запрос таблицы исполнителей - неправильный путь.


Другой метод, который я исследовал, это выполнение запроса в списке песен:

q = Song.query
q = q.join(Artist)
q = q.filter(Song.name.like("%" + i + "%"))

Однако, в этом случае q.all () - это список песен, ихотя они содержат имя исполнителя, они не «группируются» по имени исполнителя (мне пришлось бы выполнять ручную работу, чтобы составить список всех песен с одинаковым именем исполнителя для каждого исполнителя).то есть лучшее, что я мог сделать, это:

[song1, song2, song3, song4]

Или

artists = {}
for song in songs:
    artists[song.artist.name].append(song.name)
    # or initialize artists[song.artist.name] = [song.name,]

Все эти решения, которые я пробовал, по-видимому, связаны с какими-то ручными задачами в части программы Pythonи я чувствую, что должен быть способ улучшить мое решение, чтобы в большей степени полагаться на SQL. Есть ли способ запросить таблицу и вернуть группы, сгруппированные / перечисленные по «одной» части отношения «многие к одному», только соответствующие «многим», которые соответствуют определенным критериям?

...