2009-12-29 10 views
41

Existe-t-il un moyen de spécifier le champ de requête parent à partir d'une sous-requête dans mySQL?Comment spécifier le champ de requête parent à partir d'une sous-requête dans mySQL?

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

Dans la base de données, chaque message contient: id (PK) et parent_id (l'ID du parent post). Si le poste est lui-même un parent, alors son parent_id est mis à 0.

J'essaye d'écrire une requête mySQL qui trouvera tous les messages de parent et le nombre d'enfants que le parent 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 partie la plus délicate est que le premier id ne sait pas qu'il doit se référer à la deuxième id qui est en dehors de la sous-requête. Je sais que je peux faire SELECT id AS id_tmp et puis se référer à l'intérieur de la sous-requête, mais si je veux aussi retourner l'id et garder "id" comme nom de colonne, alors je devrais faire une requête qui renvoie moi 2 colonnes avec les mêmes données (ce qui me semble salissante)

$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 façon désordonnée fonctionne très bien, mais je me sens une occasion d'apprendre quelque chose ici, donc je pensais que je poste la question.

Répondre

60

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 alias sur le 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"; 
+0

Et si j'ai pris l'alias pour p1.id? –

+0

Qu'est-ce que cela signifie? "pris alias pour"? – Don

+0

Si j'ai pris un alias comme: "SELECT p1.id comme MYID," alors quelle sera la requête? –

2

Donnez les 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"; 
4

Vous pouvez 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, utiliser l'alias de la table principale dans la sous sélectionnez

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

La syntaxe suivante fonctionne dans Oracle. Pouvez-vous tester si la même chose fonctionne dans MYSQL aussi? Il est appelé sous-requête scalaire dans Oracle.

Vous auriez juste besoin d'alias les deux tables différemment pour les distinguer si vous utilisez deux fois la même table.

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

Merci Don. J'ai eu une requête imbriquée comme indiqué ci-dessous et une clause WHERE dans ce n'était pas en mesure 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 */ 
); 

Alors, je viens d'ajouter l'alias v1 à nouveau à l'intérieur du JOIN. Ce qui l'a fait fonctionner.

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 */ 
); 

Espérons que cela sera utile pour quelqu'un.