2017-10-10 9 views
1

J'écris une application simple qui commande mes médias (images, musique, vidéos ...). Chaque média peut être associé à 0 à plusieurs tags. Mon but est d'avoir une interface utilisateur où je peux rechercher mes médias (par exemple, montrer des images et des vidéos marquées comme% hol%, et retourner les deux photos marquées de vacances et les photos marquées hollywood).Limiter un résultat de requête sql avec jointure et conditions

Voilà ma base de données:

Table medias 
+---------+--------------+------+-----+---------+----------------+ 
| Field | Type   | Null | Key | Default | Extra   | 
+---------+--------------+------+-----+---------+----------------+ 
| id  | int(11)  | NO | PRI | NULL | auto_increment | 
| path | varchar(400) | NO | UNI | NULL |    | 
| type | varchar(5) | NO |  | NULL |    | 
| libelle | varchar(200) | NO |  | NULL |    | 
| ratings | int(2)  | NO |  | NULL |    | 
+---------+--------------+------+-----+---------+----------------+ 

Table tags 
+---------+--------------+------+-----+---------+----------------+ 
| Field | Type   | Null | Key | Default | Extra   | 
+---------+--------------+------+-----+---------+----------------+ 
| id  | int(11)  | NO | PRI | NULL | auto_increment | 
| libelle | varchar(200) | NO | UNI | NULL |    | 
+---------+--------------+------+-----+---------+----------------+ 

Table medias_tags 
+----------+---------+------+-----+---------+-------+ 
| Field | Type | Null | Key | Default | Extra | 
+----------+---------+------+-----+---------+-------+ 
| id_media | int(11) | NO | PRI | NULL |  | 
| id_tag | int(11) | NO | PRI | NULL |  | 
+----------+---------+------+-----+---------+-------+ 

Comme je l'ai beaucoup de médias, je devais limiter le résultat. Donc dans mon front-end, j'ai fait un système de pagination, et interroger mes médias en fonction de la page que je suis (par exemple, si je suis sur la page 3, j'ai mis LIMIT 20 OFFSET 60 dans ma déclaration sql).

Maintenant j'essaye de filtrer mes médias. J'ai une barre de recherche, et si je tape 'hol', je veux obtenir 20 médias avec tagged comme '% hol%' (vacances, hollywood ...)

Obtenir des médias filtrés fonctionne, mais je ne sais pas comment obtenir exactement 20 médias.

Voilà ma requête sql sans filtrage:

SELECT 
medias.id, medias.path, medias.type, medias.libelle as libelle, medias.ratings, tags.libelle as tag 
FROM (select * from medias LIMIT ? OFFSET ?) medias 
left outer join medias_tags on medias.id = medias_tags.id_media 
left outer join tags on tags.id = medias_tags.id_tag 

Et voici ma requête sql filtrage:

SELECT 
medias.id, medias.path, medias.type, medias.libelle as libelle, medias.ratings, tags.libelle as tag 
FROM medias 
left outer join medias_tags on medias.id = medias_tags.id_media 
left outer join tags on tags.id = medias_tags.id_tag 
WHERE tags.libelle LIKE ? [OR tags.libelle LIKE ? ...] 

(derniers paramètres sont mes tags)

Les deux travaux de recherche, mais je Impossible de trouver un moyen de limiter mon résultat filtré. Voici un exemple de mon résultat de la requête de filtrage:

+----+-------------+-------+-------------------+---------+------------+ 
| id | path  | type | libelle   | ratings | tag  | 
+----+-------------+-------+-------------------+---------+------------+ 
| 11 | mock/02.jpg | PHOTO | 02.jpg   |  0 | dark  | 
| 1 | mock/03.jpg | PHOTO | Purple   |  5 | wallpapper | 
| 3 | mock/01.jpg | PHOTO | Wave    |  5 | wave  | 
| 3 | mock/01.jpg | PHOTO | Wave    |  5 | wallpapper | 
+----+-------------+-------+-------------------+---------+------------+ 

Comment puis-je limiter mon résultat de filtrage pour revenir seulement n différent id médias? Existe-t-il une solution SQL pure? Peut-être avec des procédures stockées?

Merci!

EDIT:

Voici un résultat que je voudrais avec limite = 7:

+----+-------------+-------+-------------------+---------+------------+ 
| id | path  | type | libelle   | ratings | tag  | 
+----+-------------+-------+-------------------+---------+------------+ 
| 11 | mock/02.jpg | PHOTO | 02.jpg   |  0 | dark  | 
| 7 | mock/01.jpg | PHOTO | NEWLY ADDED MEDIA |  8 | wallpapper | 
| 2 | mock/02.jpg | PHOTO | Night    |  5 | wallpapper | 
| 2 | mock/02.jpg | PHOTO | Night    |  5 | dark  | 
| 1 | mock/03.jpg | PHOTO | Purple   |  5 | wallpapper | 
| 4 | mock/03.jpg | PHOTO | Purple 2   |  5 | wallpapper | 
| 5 | mock/03.jpg | PHOTO | Purple 3 EDITED |  8 | wallpapper | 
| 3 | mock/01.jpg | PHOTO | Wave    |  5 | wave  | 
| 3 | mock/01.jpg | PHOTO | Wave    |  5 | wallpapper | 
+----+-------------+-------+-------------------+---------+------------+ 

Je 9 lignes, mais seulement 7 id médias Services distincts. Chaque média a un tag comme '% a%'.

EDIT 2: quelqu'un a posté une réponse, mais l'a supprimée. Son idée était de concaténer les tags, ce qui serait également une bonne solution.

Quelque chose comme ça:

+----+-------------+-------+-------------------+---------+------------+ 
| id | path  | type | libelle   | ratings | tag  | 
+----+-------------+-------+-------------------+---------+------------+ 
| 11 | mock/02.jpg | PHOTO | 02.jpg   |  0 | dark  | 
| 7 | mock/01.jpg | PHOTO | NEWLY ADDED MEDIA |  8 | wallpapper | 
| 2 | mock/02.jpg | PHOTO | Night    |  5 | wallpapper, dark | 
| 1 | mock/03.jpg | PHOTO | Purple   |  5 | wallpapper | 
| 4 | mock/03.jpg | PHOTO | Purple 2   |  5 | wallpapper | 
| 5 | mock/03.jpg | PHOTO | Purple 3 EDITED |  8 | wallpapper | 
| 3 | mock/01.jpg | PHOTO | Wave    |  5 | wave, wallpapper  | 
+----+-------------+-------+-------------------+---------+------------+ 

Mais je ne sais pas comment écrire cette requête sql ...

+0

[Ce poste] (https://stackoverflow.com/questions/13525656/limit-a-left-join-on-the-first-table) peut aider. – mseifert

+0

Merci mseifert. J'ai regardé ce post, mais cela ne semble pas résoudre mon problème. La sous-requête utilisée pour limiter les résultats est ce que j'utilise sur ma première requête pour obtenir tous les médias, mais cela ne marche pas pour les résultats de filtrage, car j'essaie de limiter la table A, mais ma condition est sur la table jointe B. – Rylyn

+1

avec les balises concaténées est super et rend l'écriture de la requête beaucoup plus facile. –

Répondre

1

Utilisez GROUP_CONCAT pour créer une chaîne de balise par média et rejoignez ce résultat.Ensuite, appliquez votre clause limite comme on le souhaite

select 
    medias.id, 
    medias.path, 
    medias.type, 
    medias.libelle, 
    medias.ratings, 
    mtags.tags 
from medias 
left outer join 
(
    select id_media, group_concat(tags.libelle order by tags.libelle) as tags 
    from medias_tags 
    join tags on tags.id = medias_tags.id_tag 
    group by id_media 
) mtags on mtags.id_media = medias.id 
order by medias.id 
limit 20 offset 60; 
+0

Il semble fonctionner parfaitement et est très lisible, merci! – Rylyn

0

Attendez-vous comme ça?

SELECT 
medias.id, medias.path, medias.type, medias.libelle as libelle, medias.ratings, tags.libelle as tag 
FROM medias 
left outer join medias_tags on medias.id = medias_tags.id_media 
left outer join tags on tags.id = medias_tags.id_tag 
WHERE tags.libelle LIKE ? [OR tags.libelle LIKE ? ...] 
order by medias.id 
limit 0,10 

ici limite est utilisée pour la première 10 enregistrement. vous pouvez utiliser la procédure stockée pour passer les deux paramètres de limite et choisir le résultat filtré

+0

Malheureusement non, je reçois 10 enregistrements, pas 10 médias. Comme certains médias ont de nombreux tags, ils sont renvoyés plus d'une fois dans le résultat. La lecture de cette requête renvoie 10 enregistrements, mais seulement 4 médias. Mais merci quand même ! – Rylyn

+0

Pouvez-vous partager la démo pour votre résultat attendu? –

+1

Bien sûr, j'ai édité mon message original pour ajouter le résultat attendu :) – Rylyn