web-dev-qa-db-fra.com

ID de la table parent de l'utilisateur dans la sous-requête imbriquée

SELECT users.*,(SELECT COUNT(user_id) AS mutual_connection FROM 
                (SELECT user_id 
                       FROM (
                                SELECT sender_id AS user_id 
                                FROM `connections`
                                WHERE receiver_id=users.id AND status='2' 
                                UNION 
                                SELECT receiver_id AS user_id 
                                FROM `connections` 
                                WHERE sender_id=users.id AND status='2'
                        ) tempUser
                        WHERE user_id IN (
                                  SELECT sender_id AS user_id
                                  FROM `connections` 
                                  WHERE receiver_id='4' AND status='2'
                                  UNION 
                                  SELECT receiver_id AS user_id 
                                  FROM `connections` WHERE sender_id='4' AND status='2') 
                         GROUP BY user_id) 
                as mutualConnection)

     FROM users

Erreur:

# 1054 - Colonne inconnue 'users.id' dans 'clause where'

Comment utiliser la valeur de passe pour sous-interroger

5

MySQL interdit de référencer les colonnes de niveau externe plus profondément qu'un niveau d'imbrication. Cependant, votre requête fait référence à users.id Sur trois niveaux.

Ce dont vous avez besoin, par conséquent, est de réécrire la sous-requête corrélée de telle manière que, même si elle utilise des requêtes imbriquées, la corrélation avec le niveau externe ne soit pas imbriquée, quelque chose comme ceci:

(
  SELECT
    COUNT(*)
  FROM
    (
      SELECT ...
    ) AS mutualConnection
  WHERE
   ... = users.id
)

La tâche est assez difficile en raison de la façon dont votre sous-requête semble être corrélée avec la requête principale. Si je comprends bien, la logique est la suivante:

Pour chaque utilisateur, recherchez le nombre de connexions distinctes (utilisateurs) qui sont également connectées à un certain autre utilisateur (dans ce cas, l'utilisateur ID='4').

Vous récupérez donc une colonne collectée dans l'une des deux colonnes connections, sender_id Et receiver_id, Selon que l'autre correspond à users.id. Après la récupération, vous vérifiez que le sender_id Ou receiver_id Récupéré figure parmi les connexions de l'utilisateur 4. Enfin, vous comptez toutes les occurrences distinctes de la colonne résultante ( qui, je le répète, est un mélange de sender_id et receiver_id).

Voici comment procéder sans les nombreux niveaux d'imbrication que vous avez tentés et en conservant toutes les corrélations au même niveau:

SELECT
  u.*,
  (
    SELECT
      COUNT(DISTINCT CASE u.id WHEN c.sender_id THEN c.receiver_id ELSE c.sender_id END)
    FROM
      connections AS c
    WHERE
      c.status = '2'
      AND u.id IN (c.sender_id, c.receiver_id)
      AND (CASE u.id WHEN c.sender_id THEN c.receiver_id ELSE c.sender_id END)
      IN  (
            SELECT sender_id AS user_id
            FROM   connections 
            WHERE  receiver_id = '4' AND status = '2'
            UNION 
            SELECT receiver_id AS user_id 
            FROM   connections 
            WHERE  sender_id = '4' AND status= '2'
          )
  ) AS mutual_connection_count
FROM
  users AS u
;

L'expression CASE est la colonne user_id De la table dérivée tempUser de votre requête. Il est utilisé dans la fonction COUNT ainsi que dans la clause WHERE (le prédicat IN). Habituellement, une telle répétition de code est éliminée par imbrication. Mais l'imbrication ne peut pas être utilisée ici en raison de la limitation MySQL mentionnée au début de ce post. Ainsi, la répétition du code est le prix à payer pour le contourner. Heureusement, il n'y en a pas beaucoup dans ce cas précis.

9
Andriy M

Vous devez déplacer votre WHERE user_id = users.id clause à la première sous-requête corrélée.

create table connections(user_id int, sender_id int, receiver_id int, status int);
create table users(id int);
SELECT users.*,
       (SELECT sender_id
        FROM   connections
        WHERE  receiver_id = users.id
       ) 1_level
FROM users;
 id | 1_level 
 -: | ------: 
SELECT users.*,
       (SELECT sender_id
        FROM   (SELECT receiver_id as sender_id
                FROM   connections
                WHERE  sender_id = users.id
               ) 2_level 
       ) 1_level
FROM users;
 Colonne inconnue 'users.id' dans 'clause where' 
SELECT users.*,
       (SELECT COUNT(user_id) AS mutual_connection 
        FROM 
             (SELECT user_id 
              FROM 
                   (SELECT sender_id AS user_id 
                    FROM   connections
                    WHERE  status = '2' 
                    UNION 
                    SELECT receiver_id AS user_id 
                    FROM   connections 
                    WHERE  status = '2'
                   ) tempUser
              WHERE user_id IN (SELECT sender_id AS user_id
                                FROM   connections 
                                WHERE  receiver_id = '4' AND status = '2'
                                UNION 
                                SELECT receiver_id AS user_id 
                                FROM   connections 
                                WHERE  sender_id = '4' AND status= '2') 
              GROUP BY user_id) as mutualConnection
        WHERE user_id = users.id  #<<<-------------- Here
       ) uid
FROM users
 id | uid 
 -: | -: 

dbfiddle ici

1
McNets