Подтвердить что ты не робот

Запрос "один ко многим", выбирающий всех родителей и один верхний дочерний элемент для каждого родителя

Существуют две таблицы SQL:

Parents:
+--+---------+
|id|   text  |
+--+---------+
| 1|  Blah   |
| 2|  Blah2  |
| 3|  Blah3  |
+--+---------+

Childs
+--+------+-------+
|id|parent|feature|
+--+------+-------+
| 1|   1  |  123  |
| 2|   1  |   35  |
| 3|   2  |   15  |
+--+------+-------+

Я хочу выбрать с одним запросом каждую строку из таблицы "Родители" и для каждой отдельной строки из таблицы "Дети" с соотношением "родительский" - "id" и наибольшее значение столбца "функция". В этом примере результат должен быть:

+----+------+----+--------+---------+
|p.id|p.text|c.id|c.parent|c.feature|
+----+------+----+--------+---------+
|  1 | Blah |  1 |    1   |    123  |
|  2 | Blah2|  3 |    2   |    15   |
|  3 | Blah3|null|   null |   null  |
+----+------+----+--------+---------+

Где p = родительская таблица и c = таблица для детей

Я попытался ЛЕВАТЬ ВНУТРЕННУЮ СОЕДИНЕНИЕ И ГРУППУ, но MSSQL Express сказал мне, что запрос с GROUP BY требует функции Aggregate для каждого поля, отличного от Groupped. И я не хочу группировать их всех, а скорее выбирать верхнюю строку (с пользовательским упорядочением).

Я полностью из идей...

4b9b3361

Ответ 1

select p.id, p.text, c.id, c.parent, c.feature
from Parents p
left join (select c1.id, c1.parent, c1.feature
             from Childs c1
             join (select p1.id, max(c2.feature) maxFeature
                     from Parents p1
                left join Childs c2 on p1.id = c2.parent
            group by p1.id) cf on c1.parent = cf.id 
                              and c1.feature = cf.maxFeature) c
on p.id = c.parent

Ответ 2

Использование CTE (SQL Server 2005 +):

WITH max_feature AS (
   SELECT c.id,
          c.parent,
          MAX(c.feature) 'feature'
     FROM CHILD c
 GROUP BY c.id, c.parent)
   SELECT p.id,
          p.text,
          mf.id,
          mf.parent,
          mf.feature
     FROM PARENT p
LEFT JOIN max_feature mf ON mf.parent = p.id

Не эквивалент CTE:

   SELECT p.id,
          p.text,
          mf.id,
          mf.parent,
          mf.feature
     FROM PARENT p
LEFT JOIN (SELECT c.id,
                  c.parent,
                  MAX(c.feature) 'feature'
             FROM CHILD c
         GROUP BY c.id, c.parent) mf ON mf.parent = p.id

В вашем вопросе отсутствуют детали для обработки таймерных выключателей (когда значения 2+ CHILD.id имеют одинаковое значение функции). Ответ агента_9191 использует TOP 1, но это займет первое, которое будет возвращено, а не обязательно то, которое вы хотите.

Ответ 3

Это должно работать:

SELECT p.id, p.text, c.id, c.parent,c.feature
FROM parent p
 LEFT OUTER JOIN (SELECT TOP 1 child.id,
                               child.parent,
                               MAX(child.feature)
                  FROM child
                  WHERE child.parent = p.id
                  GROUP BY child.id, child.parent
                  ) c ON p.id = c.parent

Ответ 4

запрос manji не обрабатывает тай-брейки для функции max. Вот мой метод, который я тестировал:

;WITH WithClause AS (SELECT p.id, p.text, 
        (SELECT TOP 1 c.id from childs c 
            where c.parent = p.id order by c.feature desc) 
        AS BestChildID
    FROM Parents p) 
SELECT WithClause.id, WithClause.text, c.id, c.parent, c.feature
FROM WithClause 
LEFT JOIN childs c on WithClause.BestChildID = c.id

Ответ 5

Если вам нужно присоединиться к другому столбцу MAX и любым столбцам, описанным в группе, закрыв вложенный выбор, вы можете использовать функцию APPLY. Это простейшее решение. Вы также можете использовать оператор WITH. Но это выглядит сложнее.

SELECT p.id, p.text, CHILD_ROW.ANY_COLLUMN
FROM parent p
OUTER APPLY (SELECT TOP 1 child.ANY_COLLUMN
                  FROM child
                  WHERE child.parent = p.id
                  ORDER BY child.feature DESC 
                  ) CHILD_ROW