oracle 为什么要使用group by子查询在Where之后重复行?

rsl1atfo  于 2023-03-01  发布在  Oracle
关注(0)|答案(1)|浏览(166)

我的目标是获得一个产品ID最后更新状态的列表,下面有两个表。问题是,当我只希望收到最新的日期时,我得到了额外的行。
如果我测试单个查询以获取最新的ID/日期,我会获得正确的行数。当我尝试将产品表与之组合以添加更多描述性信息时,我会获得一些返回两行的ID。通常是最后两个状态,但不是每个ID都是这样。
如果我看一下日期,似乎我得到了最后两个状态更新,而不是像我所期望的那样只得到最近的日期。

select ID, max(Last_Updated) from Transactions group by ID <-- works fine 

select p.ID, p.Product, T.Last_Updated from Products P  <-- things start to get weird
inner join Transactions T on p.ID = T.ID
where p.ID in (1,2,3)
and T.Last_Updated in (select ID, max(Last_Updated) from Transactions group by ID)
order by p.ID desc
    • 产品表**

| 识别号|产品|
| - ------|- ------|
| 1个|蓝莓松饼|
| 第二章|巧克力曲奇|
| 三个|苹果|

    • 交易记录表**

| 识别号|现况|上次更新日期|
| - ------|- ------|- ------|
| 1个|购入|2023年1月2日上午11:16:05|
| 1个|增加存货|2023年1月2日上午11:00:01|
| 1个|显示的|2023年1月2日上午11时05分22秒|
| 1个|删除库存|2023年1月2日上午11时17分12秒|
| 第二章|等等|等等|
| 三个|等等|等等|

    • 实际结果**

| 识别号|产品|现况|上次更新日期|
| - ------|- ------|- ------|- ------|
| 1个|蓝莓松饼|购入|2023年1月2日上午11:16:05|
| 1个|蓝莓松饼|删除库存|2023年1月2日上午11时17分12秒|
| 三个|巧克力曲奇|删除库存|2023年1月2日上午11时25分11秒|
| 第二章|苹果|删除库存|2023年1月2日上午11:22:35|

    • 预期成果**

| 识别号|产品|现况|上次更新日期|
| - ------|- ------|- ------|- ------|
| 1个|蓝莓松饼|删除库存|2023年1月2日上午11时17分12秒|
| 三个|巧克力曲奇|删除库存|2023年1月2日上午11时25分11秒|
| 第二章|苹果|删除库存|2023年1月2日上午11:22:35|

zbsbpyhn

zbsbpyhn1#

在聚合查询中添加属性列时,必须将它们包含在GROUP BY中(这会更改聚合的粒度),或者对它们应用聚合(如MAX),这会通过混合不同行的值而给予不希望的结果。
您的最后一个查询有两个问题:

and T.Last_Updated in (select ID, max(Last_Updated) from Transactions group by ID)

您在父级(last_updated)中有一列,并将其应用于子查询中的两列。更正后,它将为:

and (p.pid,T.Last_Updated) in (select ID, max(Last_Updated) from Transactions group by ID)

但是,如果last_updated的粒度为1秒,并且同一日期有多条记录,则使用此方法仍可以获得比所需更多的行。它还可能需要在父块和子查询之间复制大量逻辑。
以下是一些其他选项:
如果只需要事务中的last_updated:

SELECT p.*,
           (SELECT MAX(t.last_updated)
              FROM Transactions T
             WHERE p.ID = T.ID) last_updated
      FROM Products P
     WHERE p.ID in (1,2,3)

如果需要事务处理中的其它列:

SELECT *
  FROM (SELECT p.*,
               t.othercol1,
               t.othercol2,
               ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY t.last_updated DESC) seq
          FROM Products P
               inner join Transactions T on p.ID = T.ID
         WHERE p.ID in (1,2,3))
 WHERE seq = 1

相关问题