在查询中使用PARTITION BY返回select的最大值

时间:2017-09-07 06:19:07

标签: sql-server tsql sql-server-2012

我需要返回按reference3分组的最后一个寄售编号(仅当有超过1条记录且具有相同的reference3时。

有没有办法使用partition by命令创建下面的查询?我做了一次尝试:

尝试使用分区:(不起作用:/)

SELECT
    SubAccountId,
    Reference3,
    ConsignmentNumber,
    MAX(ConsignmentNumber) OVER(PARTITION BY SubAccountId, Reference3) AS LastConsignmentNumber

FROM [CxGen].[dbo].[consignment] c   
GROUP BY SubAccountId, Reference3
HAVING COUNT(*) > 1

原始查询:

;WITH DuplicatedConsignments AS 
(
    SELECT Reference3, 
           SubAccountId, 
           Max(ConsignmentDate) AS ConsignmentDate

    FROM   [CxGen].[dbo].[consignment] 
    WHERE  Reference3 IN 
            (
                SELECT Reference3 
                FROM   [CxGen].[dbo].[Consignment] 
                GROUP  BY Reference3, SubAccountId 
                HAVING Count(Reference3) > 1
            ) 

    GROUP  BY Reference3, SubAccountId
) 
SELECT C.SubAccountid, 
       C.ConsignmentDate, 
       C.Reference3, 
       C.ConsignmentNumber, 
       C.CreatedOn 
FROM   [CxGen].[dbo].[consignment] C 
       INNER JOIN DuplicatedConsignments dc 
               ON C.reference3 = dc.reference3 
                  AND C.consignmentdate = dc.consignmentdate 
                  AND C.subaccountid = dc.subaccountid 

WHERE C.ConsignmentDate > GETDATE()-1

ORDER  BY C.Reference3, 
          C.SubaccountId, 
          C.ConsignmentNumber

预期结果:

    +--------------+-----------------+------------+-------------------+-----------------+
    | SubAccountid | ConsignmentDate | Reference3 | ConsignmentNumber |    CreatedOn    |
    +--------------+-----------------+------------+-------------------+-----------------+
    |         2070 | 7/09/2017 14:09 |    1279152 | DNZ0322457        | 7/09/2017 14:09 |
    |         1065 | 7/09/2017 15:42 |    1647907 | AULGP00031023     | 7/09/2017 15:42 |
    |         1065 | 7/09/2017 9:30  |    1653615 | AULGP00031009     | 7/09/2017 9:30  |
    |         1085 | 6/09/2017 16:52 |    1661307 | 6X31222878        | 6/09/2017 16:52 |
    |         1085 | 6/09/2017 16:52 |    1661308 | 6X31222877        | 6/09/2017 16:52 |
    |         1085 | 6/09/2017 16:40 |    1661311 | 6X31222871        | 6/09/2017 16:40 |
    |         1085 | 6/09/2017 16:30 |    1661312 | 6X31222853        | 6/09/2017 16:30 |
    |         1085 | 6/09/2017 16:56 |    1661318 | 6X31222879        | 6/09/2017 16:56 |
    |         1085 | 6/09/2017 16:41 |    1661320 | 6X31222872        | 6/09/2017 16:41 |
    |         1085 | 6/09/2017 16:42 |    1661321 | 6X31222873        | 6/09/2017 16:42 |
    |         1085 | 6/09/2017 16:43 |    1661322 | 6X31222874        | 6/09/2017 16:43 |
    |         1085 | 6/09/2017 17:11 |    1661323 | IA0017426243      | 6/09/2017 17:11 |
    |         1085 | 6/09/2017 16:44 |    1661324 | ia0017426030      | 6/09/2017 16:44 |
    |         1085 | 6/09/2017 16:51 |    1661325 | 6X31222876        | 6/09/2017 16:51 |
    |         1085 | 6/09/2017 16:51 |    1661326 | ia0017426031      | 6/09/2017 16:51 |
    |         1085 | 6/09/2017 16:55 |    1661352 | IA0017426032      | 6/09/2017 16:55 |
    |         1085 | 7/09/2017 16:21 |    1661440 | IA0017426261      | 7/09/2017 16:21 |
    |         2060 | 7/09/2017 15:56 |    1662227 | 2.3601E+12        | 7/09/2017 15:56 |
    |         2060 | 7/09/2017 15:49 |    1663004 | NULL              | 7/09/2017 15:49 |
    +--------------+-----------------+------------+-------------------+-----------------+

2 个答案:

答案 0 :(得分:1)

如果您要查找分区的最后一个值,则应使用LAST_VALUE代替MAX

LASTVALUE(ConsignmentNumber) 
OVER 
(PARTITION BY SubAccountId, Reference3 ORDER By youOrderCol) AS LastConsignmentNumber

您还需要指定一个确定每个分区内顺序的字段。在ORDER BY子句中的OVER中使用此字段。

您的查询可能如下所示:

;With LastValCTE AS (
   SELECT SubAccountId,
          Reference3,
          LASTVALUE(ConsignmentNumber) 
          OVER 
          (PARTITION BY SubAccountId, Reference3 
          ORDER By youOrderCol) AS LastConsignmentNumber
   FROM [CxGen].[dbo].[consignment] 
)
SELECT DISTINCT
    c1.SubAccountId,
    c1.Reference3,    
    c2.LastConsignmentNumber
FROM [CxGen].[dbo].[consignment] AS c1 
JOIN  LastValCTE AS c2 
   ON c1.SubAccountId = c2.SubAccountId AND c1.Reference3 = c2.Reference3
GROUP BY c1.SubAccountId, c1.Reference3
HAVING COUNT(*) > 1

此查询返回每个(SubAccountId, Reference3)组的最后一个值。为每个组返回一条记录。过滤掉只有一条记录的组。

如果您想获取每个组的所有记录,那么您可以使用以下查询:

;With LastValCTE AS (
   SELECT SubAccountId,
          Reference3,
          ConsignmentNumber,
          COUNT(*) OVER (PARTITION BY SubAccountId, Reference3) AS cnt,
          LASTVALUE(ConsignmentNumber) 
          OVER 
          (PARTITION BY SubAccountId, Reference3 
          ORDER By youOrderCol) AS LastConsignmentNumber
   FROM [CxGen].[dbo].[consignment] 
)
SELECT SubAccountId,
       Reference3,
       ConsignmentNumber,
       LastConsignmentNumber
FROM LastValCTE 
WHERE cnt > 1 

答案 1 :(得分:0)

我会按如下方式对您的查询进行短语。迭代表中的每个帐户/参考组,并为每个记录分配计数和密集排名。然后只保留计数超过1且密集等级为1的记录。

SELECT
    t.SubAccountId,
    t.Reference3,
    t.ConsignmentNumber
FROM
(
    SELECT
        SubAccountId,
        Reference3,
        ConsignmentNumber,
        COUNT(*) OVER (PARITION BY SubAccountId, Reference3) cnt,
        DENSE_RANK() OVER(PARTITION BY SubAccountId, Reference3) AS dr
    FROM [CxGen].[dbo].[consignment] c
) t
WHERE
    t.cnt > 1 AND t.dr = 1;