【问题标题】:Oracle: select just last update of dateOracle:仅选择日期的最后更新
【发布时间】:2021-08-20 12:22:51
【问题描述】:

我有以下查询返回:100 行

SELECT uni_id, uni_mast_id, uni_type
  FROM UNIVERSITIES 
 WHERE uni_master ='SO88'AND uni_stat= 'OK'

现在我需要与另一个表进行连接,然后获取当天的最后一个条目:

SELECT uni_id, uni_teach_name, MAX(cal_update), cal_status
  FROM UNIVERSITIES
  LEFT JOIN CALENDAR
    ON unı_id = cal_id
 WHERE uni_master = 'SO88'
   AND uni_stat = 'OK'
   AND cal_name = 'REGISTRED'
 GROUP BY uni_id, uni_teach_name, uni_stat
 ORDER BY cal_update

但是这个查询给了我 102 条记录,因为 cal_update 出现了 2 次。 以日期为例:22-OCT-2020 11:34:55 另一个为相同的uni_id 22-OCT-2020 11:30:22

我只想获得该日期的最大日期,而不是两者。 在这种情况下,带有连接的查询需要返回与第一个选择查询相同的记录。

【问题讨论】:

  • 数据库的版本是多少?

标签: sql oracle join oracle11g


【解决方案1】:

我认为你可以使用row_number()

SELECT UNI_ID, UNI_TEACH_NAME, CAL_UPDATE, CAL_STATUS
FROM (SELECT U.UNI_ID, U.UNI_TEACH_NAME, C.CAL_UPDATE, C.CAL_STATUS,
             ROW_NUMBER() OVER (PARTITION BY U.UNI_ID, TRUNC(C.CAL_UPDATE) ORDER BY C.CAL_UPDATE DESC) as seqnum
      FROM UNIVERSITIES U LEFT JOIN
           CALENDAR C
           ON U.UNI_ID = C.CAL_ID AND C.CAL_NAME = 'REGISTRED'
      WHERE U.UNI_MASTER = 'SO88' AND
            U.UNI_STAT= 'OK'                
     ) UC
WHERE seqnum = 1;

我必须猜测这些列的来源,因为问题不清楚。如果您使用的是LEFT JOIN,则来自CALENDAR 的任何过滤列都应位于ON 子句中。

【讨论】:

  • 它让我缺少关于这个地方的右括号来自 UNIVERSITIES U CALENDAR C
  • 如果我在括号内运行查询,它会给我消息:SQL 命令没有正确结束当然没有别名
  • @StoreCode - 在UNIVERSITIES UCALENDAR C 之间缺少JOIN 关键字。我在答案中添加了LEFT JOIN;但是在 where 子句中有 C.CAL_NAME 会将其转回内部连接;因此,如果您确实需要外连接,请将该子句移到 WHERE 之前。
  • @StoreCode 。 . . cal_update 不会被截断,但每天应该只有一个。如果您只想要最新的,请从partition by 中删除trunc()
  • @StoreCode 。 . . seqnum的计算保证每天每个uni_id只有一行。
【解决方案2】:

您可以替换查询的最后一部分,同时将 MAX(cal_update) 别名为 cal_update ,如

ORDER BY cal_update DESC 
FETCH FIRST 1 ROW WITH TIES

对于 DB 版本 12c+,按相关列降序排列,以便为该列选择具有最新值的记录。

WITH TIES 选项代表所有记录具有相同的日期时间值,可以替换为ONLY,以便即使发生这些情况也只带一行。

call_status(在选择列表中)列应该被删除,它是一个非聚合列

【讨论】:

  • 我们使用 oracle 11,您的建议不起作用,对不起那个 oracle ide:19.1
  • 这不会返回单行吗?而不是每所大学一行?
  • 是的,@AlexPoole 在这种情况下你是对的,只是被视为一般情况,没有考虑按个别大学分组......
  • 不,我的意思不是在查询 @StoreCode 中不使用 GROUP BY,当然这应该以聚合的形式存在,只是为了使最后一条记录独立于任何大学。跨度>
  • @BarbarosÖzhan:我重新查询,最后我输入了 GROUP BY UNI_TEACH_NAME, UNI_STAT ORDER BY CAL_UPDATE 但不起作用:不是 GROUP BY 表达式
【解决方案3】:

作为子查询和排名的替代方法,您可以使用KEEP...LAST

SELECT U.UNI_ID,
  U.UNI_TEACH_NAME,
  MAX(C.CAL_UPDATE) AS CAL_UPDATE,
  MAX(C.CAL_STATUS) KEEP (DENSE_RANK LAST ORDER BY C.CAL_UPDATE) AS CAL_STATUS
FROM UNIVERSITIES U
LEFT JOIN CALENDAR C
ON U.UNI_ID = C.CAL_ID
AND C.CAL_NAME = 'REGISTRED'
WHERE U.UNI_MASTER = 'SO88'
AND U.UNI_STAT= 'OK'
GROUP BY U.UNI_ID,
  U.UNI_TEACH_NAME,
  TRUNC(C.CAL_UPDATE)

我已将CAL_NAME 签入到外连接的ON 子句中;如果它在WHERE 子句中,那么它将有效地将其转回内部连接。因此,每所大学每天都会有一行更新日历:“我只想获得该日期的最大日期”。如果没有匹配的日历,它将显示日历字段的空值,因为它是外部连接。

如果您实际上只想要任何天的最新更新,那么只需从分组中删除TRUNC(C.CAL_UPDATE)

SELECT U.UNI_ID,
  U.UNI_TEACH_NAME,
  MAX(C.CAL_UPDATE) AS CAL_UPDATE,
  MAX(C.CAL_STATUS) KEEP (DENSE_RANK LAST ORDER BY C.CAL_UPDATE) AS CAL_STATUS
FROM UNIVERSITIES U
LEFT JOIN CALENDAR C
ON U.UNI_ID = C.CAL_ID
AND C.CAL_NAME = 'REGISTRED'
WHERE U.UNI_MASTER = 'SO88'
AND U.UNI_STAT= 'OK'
GROUP BY U.UNI_ID,
  U.UNI_TEACH_NAME

db<>fiddle 带有一些虚构的数据;并且(只是为了好玩)在两个地方显示带有日历名称子句的 Gordon 查询以显示差异,并显示这对于该虚拟数据得到相同的结果。 (还有an 18c version,它也显示了巴巴罗斯;回到单行。)

【讨论】:

  • 查询看起来不错,但我得到的行数更少 (44)。奇怪的是......为什么通过左连接它不会填充空匹配?
  • @StoreCode - 确实如此;您可以在 dbfiddle 中看到这一点。如果没有您的原始数据,或者至少没有您认为错误的数据的代表性版本,我不确定该建议什么。
  • 谢谢,我会和我的上级谈谈。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多