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

时间:2016-06-30 14:53:06

标签: sql oracle skip-take

当我执行时

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

我收回单曲。 (一排)

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

2 个答案:

答案 0 :(得分:1)

您正在使用where rownum < XX 而不是 order by(将在子查询中)。

因此,返回的行可以是表中的任何10行或20行。实际上,当您多次运行查询时,可能会得到不同的结果。当您在并行系统上运行查询时,这一点尤其明显 - 无论哪个线程都可以获取数据,可能会先返回它(尽管对于简单的表扫描来说这并不是那么明显)。

你需要这样的东西:

(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) ;

答案 1 :(得分:1)

设置操作UNION,INTERSECT,MINUS始终删除重复项。 (UNION有堂兄UNION ALL,但没有)。

使用MINUS时无法避免删除重复项。如果您只关心前三列(并希望保留重复项),则需要先应用MINUS操作,然后才能选择三列。

像这样:

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

进一步反思(由戈登的观察提示) - 虽然我认为这样可行(对于MINUS的两个操作数,ROWNUM将是相同的),但是为什么需要MINUS并不清楚首先,在select *的原始查询中或在我的解决方案中。

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

WHERE ROWNUM BETWEEN 11 AND 20

我没有立刻想到它,我感到愚蠢......: - )