如何在SQL Server中查找包含特定列的MIN / MAX值的所有(基于组)行?

时间:2012-12-27 22:56:33

标签: sql sql-server

我有临时表(@TempPackages),如下所示:

EntryId (PK)    PackageId    SubProductID    SubProductSequence
1               1111         17              3
2               1111         28              4
3               1111         33              1
4               1111         67              5
5               1111         122             2
6               2222         18              4
7               2222         29              5
8               2222         33              9
9               2222         103             7
10              2222         99              11
11              3333         256             5
12              3333         333             6
13              3333         789             3
14              3333         1023            2
15              3333         9845            1

我需要一个查询,它会为每个唯一SubProductSequence的行提供最小/最大PackageId值。对于上表,查询将返回:

EntryId (PK)    PackageId    SubProductID    SubProductSequence
3               1111         33              1
4               1111         67              5
6               2222         18              4
10              2222         99              11
12              3333         333             6
15              3333         9845            1

EntryId列是我在尝试解决此问题时添加的内容,因为它为我提供了一个唯一的列来连接同一个表(以确保我仍然只在我的联接表中有15行)。

我试过这个 - 只是为了得到MIN()

SELECT
    *
FROM
    @TempPackages p1
INNER JOIN
    @TempPackages p2 ON p1.EntryId = p2.EntryId
    AND p1.SubProductSequence = (
        SELECT
            MIN(SubProductSequence)
        FROM
            @DeparturesToUpdate)

显然这是错误的,因为INNER JOIN是多余的,而SELECT MIN()子句是错误的,因为它选择的行具有最小的整体序列号,而不是最小序列数字包。

有关最佳方法的任何建议吗?

3 个答案:

答案 0 :(得分:4)

一种方法是使用 ROW_NUMBER() 功能:

SELECT
    EntryId 
  , PackageId 
  , SubProductID 
  , SubProductSequence
FROM
  ( SELECT
        EntryId 
      , PackageId 
      , SubProductID 
      , SubProductSequence
      , ROW_NUMBER() OVER (PARTITION BY PackageId
                           ORDER BY SubProductSequence ASC)
          AS rna
      , ROW_NUMBER() OVER (PARTITION BY PackageId
                           ORDER BY SubProductSequence DESC)
          AS rnd
    FROM
        @TempPackages
  ) AS tmp 
WHERE
      rna = 1
   OR rnd = 1 ;

ROW_NUMBER()是一个与 OVER 子句一起使用的排名函数。它在这种情况下基本上做的是,它将行分为相同的PackageId(使用PARTITION BY PackageId完成),然后按SubProductSequence(升序或降序)对它们进行排序并分配row_number,从每个packageId的1开始。

因此,子查询将返回此项,如果它是单独运行的:

EntryId (PK)    PackageId    SubProductID    SubProductSequence  rna  rnd
3               1111         33              1                    1    5
5               1111         122             2                    2    4
1               1111         17              3                    3    3
2               1111         28              4                    4    2
4               1111         67              5                    5    1

6               2222         18              4                    1    5
7               2222         29              5                    2    4
9               2222         103             7                    3    3
8               2222         33              9                    4    2
10              2222         99              11                   5    1

15              3333         9845            1                    1    5
14              3333         1023            2                    2    4
13              3333         789             3                    3    3
11              3333         256             5                    4    2    
12              3333         333             6                    5    1

之后在外部查询中添加的WHERE条件显而易见。

答案 1 :(得分:1)

改善波希米亚人的想法 -

;WITH MinMax AS
(SELECT  PackageId ,
    MIN(SubProductSequence) [Min],
    MAX(SubProductSequence) [Max]
FROM    @TempPackages
GROUP BY PackageId )

SELECT EntryId, SubProductSequence, TP.PackageId, SubProductID FROM @TempPkges TP
INNER JOIN MinMax MM ON TP.PackageId = MM.PackageId 
AND (SubProductSequence = MM.[Min] OR SubProductSequence = MM.[Max])

然后,您可以添加自己的ORDER BY

答案 2 :(得分:0)

 WITH  t1 AS
 (SELECT PackageId,MIN(SubProductSequence) minm,MAX(SubProductSequence) maxm  
 FROM    #@TempPackages
 GROUPBY  PackageId
 )
 SELECT  pk.EntryId, pk.PackageId,pk.SubProductID,  pk.SubProductSequence 
 FROM  #@TempPackages pk INNER JOIN t1 
 ON pk.PackageId = t1.PackageId
 WHERE pk.SubProductSequence = t1.minm  OR
       pk.SubProductSequence = t1.maxm