it-roy-ru.com

Как указать родительское поле запроса из подзапроса в MySQL?

Есть ли способ указать родительское поле запроса из подзапроса в MySQL?

Например:
Я написал базовую программу типа доски объявлений на PHP.

В базе данных каждое сообщение содержит: id (PK) и parent_id (идентификатор родительского сообщения). Если сообщение само является родительским, то его parent_id устанавливается в 0.

Я пытаюсь написать запрос MySQL, который найдет каждый родительский пост и количество дочерних элементов, которые есть у родителя.

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

Сложность в том, что первый id не знает, что он должен ссылаться на второй id, который находится за пределами подзапроса. Я знаю, что могу сделать SELECT id AS id_tmp и затем обратиться к нему внутри подзапроса, но затем, если я захочу также вернуть id и сохранить «id» в качестве имени столбца, то мне придется выполнить запрос, который возвращает мне 2 столбца с одинаковыми данными (что мне кажется грязным)

$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";

Грязный путь работает отлично, но я чувствую возможность узнать кое-что здесь, поэтому я решил опубликовать вопрос.

46
justinl

Как насчет:

$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";

или если вы добавите псевдоним в p1.id, вы можете сказать:

$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

Вы можете попробовать что-то вроде этого

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

Чтобы вернуться к вашему примеру, используйте псевдоним основной таблицы в суб-выборе

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

Дайте таблицам уникальные имена:

$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

Следующий синтаксис работает в Oracle. Можете ли вы проверить, работает ли то же самое и в MYSQL? В Oracle это называется скалярным подзапросом.

Вам просто нужно по-разному совмещать две таблицы, чтобы различать их, если вы используете одну и ту же таблицу дважды.

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

Спасибо Дон. У меня был вложенный запрос, как показано ниже, и предложение WHERE не смогло определить псевдоним v1. Вот код, который не работает:

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

Итак, я просто добавил псевдоним v1 внутри JOIN. Что заставило это работать.

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

Надеюсь, это будет полезно для кого-то.

0
Mr_Green