如何在JOIN查询中使用GROUP BY

时间:2016-06-07 08:56:02

标签: sql sql-server join group-by

假设我有下面的SQL查询(Notice the JOIN):

SELECT
    bpq.Id,
    b.BatchCode,
    bpq.PartId,
    bpq.Hkid
FROM
    BoxPartsQuantity bpq
JOIN
    Batch b
ON
    bpq.BatchId = b.Id
WHERE 
    PartId = 1

并且返回的结果是:

Id     BatchCode    PartId  Hkid
137    2016-03-31   1       34361
138    2016-03-31   1       34361
139    2016-03-31   1       34361
140    2016-03-31   1       34361
141    2016-03-31   1       34361
1123   2016/04/19   1       34361
1976   2016/04/29   1       34361

我如何删除BatchCodeHkid中的重复项,假设我想要如下结果:

Id     BatchCode    PartId  Hkid
137    2016-03-31   1       34361
1123   2016/04/19   1       34361

我已尝试过以下代码:

SELECT
    bpq.Id,
    b.BatchCode,
    bpq.PartId,
    bpq.Hkid
FROM
    BoxPartsQuantity bpq
JOIN
    Batch b
ON
    bpq.BatchId = b.Id
WHERE 
    PartId = 1

GROUP BY
    b.BatchCode,
    bpq.Hkid

但是它返回了我的错误:

[SQL]SELECT
  bpq.Id,
  b.BatchCode,
  bpq.PartId,
  bpq.Hkid
FROM
  BoxPartsQuantity bpq
JOIN
  Batch b
ON
  bpq.BatchId = b.Id
WHERE 
  PartId = 1

GROUP BY
  b.BatchCode,
  bpq.Hkid
     

[Err] 42000 - [SQL Server] Column' BoxPartsQuantity.Id'在选择列表中无效,因为它不包含在聚合中   函数或GROUP BY子句。

我对我应该做什么和必须做什么非常困惑,因为我对SQL编码及其所有知识都不是很了解。谢谢

4 个答案:

答案 0 :(得分:2)

您必须对未参与GROUP BY子句的记录使用聚合函数:

SELECT
    MIN(bpq.Id),
    b.BatchCode,
    bpq.PartId,
    bpq.Hkid
FROM
    BoxPartsQuantity bpq
JOIN
    Batch b
ON
    bpq.BatchId = b.Id
WHERE 
    PartId = 1    
GROUP BY
    b.BatchCode,
    bpq.Hkid,
    bpq.PartId

上述查询还在bpq.PartId中放置了字段GROUP BY。这对分组没有任何影响,因为PartId=1返回了所有记录。对MIN字段使用bpq.Id,查询会返回每b.BatchCode, bpq.Hkid组记录的最小值,与OP中引用的预期结果一样。

答案 1 :(得分:2)

错误正在发生,因为bpq.id不是唯一的,每个组都有多个值,所以你必须选择你想要的那个(不是在所有的DBMS中,MySQL允许它,它会随机选择)一个值)。

根据您的示例,我想您需要第一个ID,因此MIN()是最佳选择:

SELECT
    min(bpq.Id),
    b.BatchCode,
    bpq.PartId,
    bpq.Hkid
FROM
    BoxPartsQuantity bpq
JOIN
    Batch b
ON
    bpq.BatchId = b.Id
WHERE 
    PartId = 1
GROUP BY
    b.BatchCode,
    bpq.Hkid,
    bpq.PartId

答案 2 :(得分:1)

以下查询将提供所需的结果: -

SELECT
distinct min(bpq.Id) over(partition by b.BatchCode,bpq.Hkid),
b.BatchCode,
bpq.PartId,
bpq.Hkid

FROM
BoxPartsQuantity bpq
JOIN
Batch b
ON
bpq.BatchId = b.Id
WHERE bpq.PartId = 1

答案 3 :(得分:0)

您遇到的错误告诉我们,选择列列表中未包含在聚合函数中的每一列也应放在Group By中。

除了@Giorgos Betsos答案旁边的要求,您还可以使用不再需要使用Group By的Row_Number,如下所示:

SELECT  Id ,
    BatchCode ,
    PartId ,
    Hkid
FROM    ( SELECT    ROW_NUMBER() OVER ( PARTITION BY b.BatchCode ORDER BY bpq.Id ) AS Rn ,
                bpq.Id ,
                b.BatchCode ,
                bpq.PartId ,
                bpq.Hkid
      FROM      BoxPartsQuantity bpq
                JOIN Batch b ON bpq.BatchId = b.Id
      WHERE     PartId = 1
    ) AS K
WHERE   Rn = 1;

在上面的查询和内部子查询中,我们首先为每个记录分配行号。为每个不同的BatchCode重置此行号,并且将根据Id列对此行号进行排序。在分配行号后,我们在外部查询中过滤行号等于1。我们使用子查询分配行号并在外部查询中过滤它的原因是,Row_number不能放在查询的Where部分内。