如何根据创建标识符和最大日期的两列选择行

Posted

技术标签:

【中文标题】如何根据创建标识符和最大日期的两列选择行【英文标题】:How to select rows based on two columns creating an identifier and the max date 【发布时间】:2021-08-19 21:01:48 【问题描述】:

我有六列。我自己创建的六列之一。将其中的两个列放在一起创建一个标识符列。我只想为标识符列的每个不同组合选择最大日期行。当我省略数量列时,我得到了预期的行数。但是,一旦我添加数量,它就会给我我不期望的行。如何只为 Identifier 列的每个不同出现选择最大日期行?

例如,当我运行此查询时...

Select 
 Distinct(L.ItemNo+' 'L.Lot) as Identifier
 ,Max(L.PostingDate)
 ,L.ItemNo
 ,L.Description
 ,L.Quantity
 ,L.Lot
From dbo.JournalLine L
Groupy by
 L.ItemNo
 ,L.Lot
 ,L.Description
 ,L.Quantity

我得到以下结果。我没想到的这一行是有 45 个苹果的那一行。

Identifier PostingDate ItemNo Description Quantity Lot
I123 LOT123 2021-06-01 I123 Celery 79 L123
I456 LOT456 2021-06-01 I456 Carrot 25 L456
I456 LOT654 2021-06-01 I654 Carrot 21 L654
I789 LOT789 2021-05-28 I789 Apple 45 L789
I789 LOT789 2021-06-01 I789 Apple 38 L789
I789 LOT555 2021-06-01 I789 Apple 11 L555

【问题讨论】:

DISTINCT 不是一个函数,它是一个设置量词,属于SELECT DISTINCT - 适用于整个选定的行。跳过那些额外的括号,直接写Select Distinct L.ItemNo+' 'L.Lot as Identifier, ... 以减少代码混乱。 【参考方案1】:

GROUP BY 子句将所有包含指定列中数据的行聚集在一起(这里 GroupBy 操作对列 L.ItemNoL.LotL.DescriptionL.Quantity 执行)并允许聚合在一列或多列上执行的函数(这里聚合在L.PostingDate上完成)。

因此,每条具有不同列组合的记录,即L.ItemNoL.LotL.DescriptionL.Quantity,将与它的重复组合的聚合一起出现。例如,考虑您的示例:-

让我们假设您的表中有以下记录:-

Identifier  PostingDate ItemNo  Description Quantity    Lot
I789 LOT789 2021-05-27  I789    Apple       45          L789
I789 LOT789 2021-05-29  I789    Apple       38          L789
I789 LOT789 2021-05-25  I789    Apple       45          L789
I789 LOT789 2021-05-28  I789    Apple       45          L789
I789 LOT789 2021-06-01  I789    Apple       38.         L789
I789 LOT555 2021-06-01  I789    Apple       11.         L555

因此,当您对IdentifierItemNoDescriptionQuantityLot 进行分组时,SQL 会理解您想要对这些列进行逻辑分组,并且它将划分数据并理解如下:-

-- Group 1
Identifier  PostingDate ItemNo  Description Quantity    Lot
I789 LOT789 2021-05-27  I789    Apple       45          L789
I789 LOT789 2021-05-25  I789    Apple       45          L789
I789 LOT789 2021-05-28  I789    Apple       45          L789

-- Group 2
Identifier  PostingDate ItemNo  Description Quantity    Lot
I789 LOT789 2021-05-29  I789    Apple       38          L789
I789 LOT789 2021-06-01  I789    Apple       38.         L789

-- Group 3
Identifier  PostingDate ItemNo  Description Quantity    Lot
I789 LOT555 2021-06-01  I789    Apple       11.         L555

现在,当您在某个特定列上的这些记录上运行任何聚合函数时,它将尝试为遇到的每个逻辑分组运行聚合函数(如上所示,在这种情况下有 3 个)

因此,在我们的例子中,聚合函数是 Max(L.PostingDate),它将选择迄今为止已识别的每个组的最大日期记录,如下所示:-

-- Group 1
Identifier  PostingDate ItemNo  Description Quantity    Lot
I789 LOT789 2021-05-28  I789    Apple       45          L789

-- Group 2
Identifier  PostingDate ItemNo  Description Quantity    Lot
I789 LOT789 2021-06-01  I789    Apple       38.         L789

-- Group 3
Identifier  PostingDate ItemNo  Description Quantity    Lot
I789 LOT555 2021-06-01  I789    Apple       11.         L555

现在最后它结合了所有记录并显示结果如下:-

-- Final Ouput
Identifier  PostingDate ItemNo  Description Quantity    Lot
I789 LOT789 2021-05-28  I789    Apple       45          L789
I789 LOT789 2021-06-01  I789    Apple       38.         L789
I789 LOT555 2021-06-01  I789    Apple       11.         L555

这就是group by 的作用方式,所以在您的情况下,如果您不希望 group by 在quantity 列上发生,您可以简单地将其从 select 查询以及 groupBy 中删除,或者如果您包括 quantity 列以分组,它将继续打印具有不同列组合的记录。

【讨论】:

【参考方案2】:

你可以使用窗口功能:

select * from (
  select * , row_number() over (partition by ItemNo,Lot order by PostingDate desc) rn
  from dbo.JournalLine
) l
where rn = 1

【讨论】:

【参考方案3】:

使用窗口函数MAX()FIRST_VALUE()分别获取最新PostingDate所在行的PostingDateQuantity的值:

SELECT DISTINCT
       ItemNo + ' ' + Lot AS Identifier,
       MAX(PostingDate) OVER (PARTITION BY ItemNo, Lot, Description) AS PostingDate,
       ItemNo,
       Description,
       FIRST_VALUE(Quantity) OVER (PARTITION BY ItemNo, Lot, Description ORDER BY PostingDate DESC) AS Quantity,
       Lot
FROM dbo.JournalLine

【讨论】:

这行得通。非常感谢您的帮助!

以上是关于如何根据创建标识符和最大日期的两列选择行的主要内容,如果未能解决你的问题,请参考以下文章

如何根据 sqlalchemy 中的两列进行过滤

根据匹配另一列标识符中所有行的列内容来选择行?

根据日期和请求数创建唯一 ID

加入创建重复行

如何将所有行的两列总和为第三列

R:根据上/下行中的值按组识别行