Bonjour,

Je suis fasse un problème que je n'arrive pas à resoudre. C'est une jointure entre trois tables. Je ne suis même pas sur que la troisième doit être jointe.

Ce que j'ai

  • Items (liste d'articles des utilisateurs)
  • Users (liste d'utilisateurs)
  • Item_Favoris (liste des articles en favoris par chaque utilisateur)

Entre Items et Users c'est assez simple. (J'utilise laravel 5.2)

 left join `Item_Favoris` on `Item_Favoris`.`item_id` = `items`.`id`

Ce que j'aimerais

Maintenant arrive la troisième table Item_Favoris. Cette table permet de mettre en favoris les Items par utilisateur.
Elles possèdes les champs id, item_id et user_id.

Ce que j'aimerais c'est : Si dans la table Item_Favoris il existe une entrée, ajouter is_favoris: 1 dans le resultat de la liste d'article. Autrement is_favoris: 0

{
    "data":
    [
    {
      "id": 1,
      "user_id": 1,
      "username": "Louis",
      "brand": "Zara",
      "size": 16,
      "price": "50",
      "is_favoris": 1
    },
   {
      "id": 2,
      "user_id": 1,
      "username": "Louis",
      "brand": "Adidas",
      "size": 23,
      "price": "16",
      "is_favoris": 0
    }
    ]
}

Ce que j'obtiens

J'obtiens un peu de tout car j'ai tout essayé (left join, CASE WHEN, whereIn, etc.).

5 réponses


neecride
Réponse acceptée

Je ne sais pas comment fonction laravel mais pour faire une jointure moi je fait ça pour mon forum

    SELECT 

        f_topics.id AS topicsid,
        f_topics.f_topic_content,
        f_topics.f_topic_name,
        f_topics.f_forum_id,
        f_topics.f_user_id,
        f_topics.f_topic_date,
        f_topics.f_topic_vu,
        f_topics.f_rep_topic_nb,
        f_topics.f_autor_topic,

        f_topics_reponse.f_topic_rep_date,
        f_topics_reponse.id AS idrep,
        f_topics_reponse.user_rep,

        f_message_view.last,
        f_message_view.user_id,

        users.id AS usersid,
        users.username,

    CASE 
          WHEN f_topics.f_topic_date > f_topics_reponse.f_topic_rep_date THEN f_topics.f_topic_date

          ELSE f_topics_reponse.f_topic_rep_date

    END AS Lastdate

    FROM f_topics

    LEFT JOIN users ON users.id = f_topics.f_user_id

    LEFT JOIN f_topics_reponse ON f_topics_reponse.f_topic_id = f_topics.id

    LEFT JOIN f_message_view ON f_message_view.topic_id = f_topics.id AND f_message_view.user_id = ?

    WHERE f_topics.f_forum_id = ?

    GROUP BY f_topics.id

    ORDER BY Lastdate DESC

Tu pourra y remarquer le GROUP BY cette requete me retourne les topic par forum avec un ORDER BY Lastdate que je fait avec le CASE ensuite je regroupe tout avec l'id du topic.

Ne connaissant pas l'ORM de Laravel, je te donne une piste.

Faire une jointure classique avec tes 2 ID (items/favoris) sur la table "Item_Favoris" ainsi qu'un "GROUP BY Items.id" (pour éviter d'avoir plusieurs lignes pour le même item).

Ensuite, pour avoir ton "is_favoris", il ne te reste plus qu'à vérifier si c'est null : Item_Favoris.id IS NULL as is_favoris
Si c'est NULL, c'est qu'il n'y a aucun favoris, et inversement.

Salut, je ferais comme @Kenor également

Juste un conseil, lorsque tu poses un problème sur un forum met le en SQL, car le mettre avec un ORM spécifique peu faire "fuire" des personnes qui auraient pu t'aider..
Egalement, j'espère que tu maîtrises bien SQL avant de passer par un ORM, petit conseil pratique : faire les requêtes en SQL puis après utiliser l'orm (pour les queries plus compliquées)

Xation
Auteur

Merci à tous pour vos réponses.

On peut utiliser SQL à 100% en brut avec laravel si on veut. Donc c'était juste une précision mais dans l'absolue ma question est sur SQL.

@Emix Je viens d'editer en SQL. Tu as raison.
Il est vrai que je ne maitrise pas parfaitement le SQL mais l'utilisation d'un ORM ne s'arrête pas là, j'aurais eu le même problème sans ORM de mon point de vue.

@neecride @Kenor Merci aux deux, quand je fais le GROUP BY items.idça regroupe mais pas dans le bon ordre. Donc j'ajoute le ORDERY BY is_favoris qui ne fait pas son boulot.

Si j'enlève le GROUP BY items.id on remarque que l'order by marche.

{
        "data":[
        {
            "id": 1,
            "user_id": 1,
            "brand": "Zara",
            "size": 16,
            "price": "50",
            "name": "Louis",
            "is_favoris": 1,
        },
        {
            "id": 1,
            "user_id": 1,
            "brand": "Zara",
            "size": 16,
            "price": "50",
            "name": "Louis",
            "is_favoris": 0,
        }
        ]
}

Mais si je le remets

{
        "data":[
        {
            "id": 1,
            "user_id": 1,
            "brand": "Zara",
            "size": 16,
            "price": "50",
            "name": "Louis",
            "is_favoris": 0,
        }
        ]
}

Une idée pourqoi ?

Voici toute la requête :

select items.id, items.user_id, items.photos, items.brand, items.size, items.price, users.name, users.avatar, users.canton, CASE WHEN favoris.user_id = ? THEN 1 ELSE 0 END AS is_favoris from items left join users on users.id = items.user_id left join item_favoris on item_favoris.item_id = items.id where (items.status = ? and items.photos != ?) and items.id not in (select solds.id from solds) group by items.id order by is_favoris desc, ascended_at desc
Xation
Auteur

Je vais répondre moi même à la dernière question. Il faut ajouter MAX() à CASE WHEN comme ceci :

max(CASE WHEN favoris.user_id = ? THEN 1 ELSE 0 END) AS is_favoris 

et le groupby et le orderby deviennent inutiles.

Pourquoi ça ne marchait pas ? Simplement parce que groupby est fait avant le orderby.