web-dev-qa-db-fra.com

Comment spécifier le champ de requête parent depuis une sous-requête dans mySQL?

Est-il possible de spécifier le champ de requête parent à partir d'une sous-requête dans MySQL?

Par exemple:
J'ai écrit un programme de base de type babillard en PHP.

Dans la base de données, chaque publication contient: id (PK) et parent_id (id de la publication parente). Si la publication est elle-même un parent, son parent_id est défini sur 0.

J'essaye d'écrire une requête de MySQL qui trouvera chaque poste parent et le nombre d'enfants qu'il a.

$query = "SELECT id, (
      SELECT COUNT(1) 
      FROM post_table 
      WHERE parent_id = id
) as num_children
FROM post_table
WHERE parent_id = 0";

La difficulté réside dans le fait que le premier id ne sait pas qu’il devrait faire référence au second id situé en dehors de la sous-requête. Je sais que je peux faire une sélection SELECT id AS id_tmp et y faire référence à l'intérieur de la sous-requête, mais si je souhaite également renvoyer l'ID et conserver "id" en tant que nom de colonne, il me faudra alors effectuer une requête renvoyant moi 2 colonnes avec les mêmes données (ce qui me semble malpropre)

$query = "SELECT id, id AS id_tmp, 
            (SELECT COUNT(1)
            FROM post_table
            WHERE parent_id = id_tmp) as num_children
         FROM post_table
         WHERE parent_id = 0";

La manière désordonnée fonctionne bien, mais je me sens comme une occasion d'apprendre quelque chose ici, alors j'ai pensé poser la question.

46
justinl

Que diriez-vous:

$query = "SELECT p1.id, 
                 (SELECT COUNT(1) 
                    FROM post_table p2 
                   WHERE p2.parent_id = p1.id) as num_children
            FROM post_table p1
           WHERE p1.parent_id = 0";

ou si vous mettez un pseudonyme sur p1.id, vous pourriez dire:

$query = "SELECT p1.id as p1_id, 
                 (SELECT COUNT(1) 
                    FROM post_table p2 
                   WHERE p2.parent_id = p1.id) as num_children
            FROM post_table p1
           WHERE p1.parent_id = 0";
67
Don

Tu pourrais essayer quelque chose comme ça

SELECT  pt.id,
        CountTable.Cnt
FROM    post_table pt LEFT JOIN
        (
            SELECT  parent_id,
                    COUNT(1) Cnt
            FROM    post_table
            WHERE   parent_id <> 0
            GROUP BY parent_id
        ) CountTable ON pt.id = CountTable.parent_id
WHERE   pt.parent_id = 0

Pour revenir à votre exemple, utilisez le alias de la table principale dans la sous-sélection

SELECT  pt.id,
        (SELECT COUNT(1) FROM post_table WHERE parent_id = pt.id) 
FROM    post_table pt
WHERE   pt.parent_id = 0
4
Adriaan Stander

Attribuez aux tables des noms uniques:

$query = "SELECT a.id, (SELECT COUNT(1) FROM post_table b WHERE parent_id = a.id) as num_children FROM post_table a WHERE a.parent_id = 0";
2
Tatu Ulmanen

La syntaxe suivante fonctionne dans Oracle. Pouvez-vous tester si la même chose fonctionne aussi dans MYSQL? Cela s'appelle une sous-requête scalaire dans Oracle.

Si vous utilisez deux fois la même table, il vous suffira d’aliaser différemment les deux tables pour les distinguer.

sql> select empno,
  2         (select dname from dept where deptno = emp.deptno) dname
  3    from emp 
  4    where empno = 7369;

     EMPNO DNAME
---------- --------------
      7369 RESEARCH

sql> select parent.empno,
  2         (select mgr from emp where empno = parent.empno) mgr
  3    from emp parent
  4    where empno = 7876;

     EMPNO        MGR
---------- ----------
      7876       7788
0
Rajesh Chamarthi

Merci Don. Comme indiqué ci-dessous, ma requête était imbriquée et une clause WHERE ne permettait pas de déterminer l'alias v1. Voici le code qui ne fonctionne pas:

Select 
    teamid,
    teamname
FROM
    team as t1
INNER JOIN (
    SELECT 
        venue_id, 
        venue_scores, 
        venue_name 
    FROM venue 
    WHERE venue_scores = (
        SELECT 
            MAX(venue_scores) 
        FROM venue as v2 
        WHERE v2.venue_id = v1.venue_id      /* this where clause wasn't working */
    ) as v1    /* v1 alias already present here */
);

Donc, je viens d'ajouter le pseudonyme v1 à nouveau dans la JOIN. Ce qui a fait que ça marche.

Select 
    teamid,
    teamname
FROM
    team as t1
INNER JOIN (
    SELECT 
        venue_id, 
        venue_scores, 
        venue_name 
    FROM venue as v1              /* added alias v1 here again */
    WHERE venue_scores = (
        SELECT 
            MAX(venue_scores) 
        FROM venue as v2 
        WHERE v2.venue_id = v1.venue_id   /* Now this works!! */
    ) as v1     /* v1 alias already present here */
);

J'espère que cela sera utile pour quelqu'un.

0
Mr_Green