一个一对多的查询选择所有的父母和一个孩子顶部为每个父(one-to-many query selec

2019-07-23 10:15发布

有两个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 =子表

我试图LEFT OUTER JOIN和GROUP BY但MSSQL快告诉我,GROUP BY该查询要求对每一个非细分电子邮件域聚合函数。 我不希望他们全部归类,而是选择最上面一行(自定义排序)。

我完全没了主意......

Answer 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


Answer 2:

使用CTE(SQL服务器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值具有相同的特征值)。 Agent_9191的答案使用TOP 1 ,但会第一时间被返回&不一定是你想要的。



Answer 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


Answer 4:

满级的查询不处理领带断路器的最大特点。 这里是我的方法,我已经测试过:

;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


Answer 5:

如果您需要加入从MAX列并通过嵌套选择关闭一组中描述的任何列的不同,你可以使用一个应用函数。 这是一个简单的解决方案。 您也可以通过运营商使用。 但是,这看起来更难。

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


文章来源: one-to-many query selecting all parents and single top child for each parent