Oracle rownum 返回错误结果
Oracle rownum returning wrong result
我正在尝试查询 return 只有来自 table 的最新行。
最初我在查询中使用 max(id)
但是当我使用序列并且我的环境是集群时,我不能依赖序列因为它是无序的。
所以我决定根据创建时间排序并使用 rownum 选择第一行。
我用了类似
的东西
SELECT A.id
FROM Table_A, Table_B B
WHERE A.status = 'COMPLETED'
AND B.name = 'some_name'
AND A.id = B.id
AND rownum = 1
order by A.Creation_Time;
这个 return 告诉我一些错误的结果,比如 42145。
如果我删除 rownum condtn 最高记录是 differnet 说 45343;
当使用 rownum
和 order by
时,您需要使用子查询。这与 where
和 order by
的计算顺序有关。所以,试试这个:
SELECT t.*
FROM (SELECT A.id
FROM Table_A JOIN
Table_B B
ON A.id = B.id
WHERE A.status = 'COMPLETED' AND B.name = 'some_name'
ORDER BY A.Creation_Time
) ab
WHERE rownum = 1;
补充一下:Oracle 12支持fetch first 1 row only
,更方便:
SELECT A.id
FROM Table_A JOIN
Table_B B
ON A.id = B.id
WHERE A.status = 'COMPLETED' AND B.name = 'some_name'
ORDER BY A.Creation_Time
FETCH FIRST 1 ROW ONLY;
你想这样做吗? (指定顺序 DESC)
SELECT A.id
FROM Table_A, Table_B B
WHERE A.status = 'COMPLETED'
AND B.name = 'some_name'
AND A.id = B.id
AND rownum = 1
order by A.Creation_Time DESC;
编辑:显然指定顺序 DESC 对您的查询至关重要。我也必须赞成戈登,因为他完全正确,您需要限制排序后返回的行,因此他建议的方法非常适合。因此,对于读到这里的任何人,我想毫无疑问地在处理 where 子句之后但在排序或聚合 (source) 之前分配 rownum。
注意:尽管 Gordon 的回答很好,但这里还有一个可能重要也可能不重要的考虑因素。似乎可能有 A.Creation_Time 的重复值,这可能会导致您看到在执行该查询时可能返回哪些重复行的不确定行为。如果可能出现该问题,Tom Kyte(与之前的 link 相同)建议将一些唯一的列值添加到 order by 子句中作为一种简单的躲避。例如:
SELECT t.id
FROM (SELECT *
FROM (SELECT A.id, A.Creation_Time
FROM Table_A A
JOIN Table_B B
ON A.id = B.id
WHERE A.status = 'COMPLETED' AND B.name = 'some_name'
)
ORDER BY Creation_Time, rowid DESC
) t
WHERE rownum = 1;
其中 ROWID 是可以达到目的的唯一伪列。
我正在尝试查询 return 只有来自 table 的最新行。
最初我在查询中使用 max(id) 但是当我使用序列并且我的环境是集群时,我不能依赖序列因为它是无序的。 所以我决定根据创建时间排序并使用 rownum 选择第一行。
我用了类似
的东西SELECT A.id
FROM Table_A, Table_B B
WHERE A.status = 'COMPLETED'
AND B.name = 'some_name'
AND A.id = B.id
AND rownum = 1
order by A.Creation_Time;
这个 return 告诉我一些错误的结果,比如 42145。 如果我删除 rownum condtn 最高记录是 differnet 说 45343;
当使用 rownum
和 order by
时,您需要使用子查询。这与 where
和 order by
的计算顺序有关。所以,试试这个:
SELECT t.*
FROM (SELECT A.id
FROM Table_A JOIN
Table_B B
ON A.id = B.id
WHERE A.status = 'COMPLETED' AND B.name = 'some_name'
ORDER BY A.Creation_Time
) ab
WHERE rownum = 1;
补充一下:Oracle 12支持fetch first 1 row only
,更方便:
SELECT A.id
FROM Table_A JOIN
Table_B B
ON A.id = B.id
WHERE A.status = 'COMPLETED' AND B.name = 'some_name'
ORDER BY A.Creation_Time
FETCH FIRST 1 ROW ONLY;
你想这样做吗? (指定顺序 DESC)
SELECT A.id
FROM Table_A, Table_B B
WHERE A.status = 'COMPLETED'
AND B.name = 'some_name'
AND A.id = B.id
AND rownum = 1
order by A.Creation_Time DESC;
编辑:显然指定顺序 DESC 对您的查询至关重要。我也必须赞成戈登,因为他完全正确,您需要限制排序后返回的行,因此他建议的方法非常适合。因此,对于读到这里的任何人,我想毫无疑问地在处理 where 子句之后但在排序或聚合 (source) 之前分配 rownum。
注意:尽管 Gordon 的回答很好,但这里还有一个可能重要也可能不重要的考虑因素。似乎可能有 A.Creation_Time 的重复值,这可能会导致您看到在执行该查询时可能返回哪些重复行的不确定行为。如果可能出现该问题,Tom Kyte(与之前的 link 相同)建议将一些唯一的列值添加到 order by 子句中作为一种简单的躲避。例如:
SELECT t.id
FROM (SELECT *
FROM (SELECT A.id, A.Creation_Time
FROM Table_A A
JOIN Table_B B
ON A.id = B.id
WHERE A.status = 'COMPLETED' AND B.name = 'some_name'
)
ORDER BY Creation_Time, rowid DESC
) t
WHERE rownum = 1;
其中 ROWID 是可以达到目的的唯一伪列。