在 MINUS 查询中指定列会产生与使用 * 不同的结果

Specifying columns in MINUS query yields different results from using *

当我执行

SELECT * FROM TABLE_NAME WHERE ROWNUM <= 20 
MINUS 
SELECT * FROM TABLE_NAME WHERE ROWNUM <= 10 

我得到的预期结果是 SKIP 10 TAKE 10(十行)

但如果我明确指定列

SELECT COL1, COL2, COL3 FROM TABLE_NAME WHERE ROWNUM <= 20 
MINUS 
SELECT COL1, COL2, COL3 FROM TABLE_NAME WHERE ROWNUM <= 10

我得到了单条记录。 (一行)

为什么会这样?我该如何解决这个问题?

您正在使用 where rownum < XX 没有 order by(这将在子查询中)。

因此,returned 行可以是 table 中的任意 10 或 20 行。事实上,当您 运行 多次查询时,您可能会得到不同的结果。当您 运行 在并行系统上进行查询时,这一点尤为明显——无论哪个线程碰巧获取数据,都可能首先 return 它(尽管对于简单的 table 扫描而言,这并不是那么明显).

你需要这样的东西:

(SELECT * FROM (SELECT * FROM TABLE_NAME ORDER BY COL1, COL2, COL3) WHERE ROWNUM <= 20)
MINUS 
(SELECT * FROM (SELECT * FROM TABLE_NAME ORDER BY COL1, COL2, COL3) WHERE ROWNUM <= 10) ;

集合运算 UNION、INTERSECT、MINUS 总是删除重复项。 (UNION 有 UNION ALL 的表亲,而 UNION ALL 没有)。

使用 MINUS 时无法避免删除重复项。如果您只关心前三列(并希望保留重复项),则需要先应用 MINUS 运算,然后才对 select 这三列进行运算。

像这样:

SELECT COL1, COL2, COL3 FROM (
    SELECT * FROM TABLE_NAME WHERE ROWNUM <= 20 
    MINUS 
    SELECT * FROM TABLE_NAME WHERE ROWNUM <= 10
);

进一步思考(由 Gordon 的观察提示)- 虽然我认为这会起作用(ROWNUM 对于 MINUS 的两个操作数是相同的),但根本行不通清楚为什么首先需要 MINUS,无论是在使用 select * 的原始查询中还是在我的解决方案中。

在所有情况下更好的解决方案是 select 一次并使用正确的 WHERE 子句:

WHERE ROWNUM BETWEEN 11 AND 20

我为没有立即考虑而感到愚蠢...:-)