使用 ROWNUM 查询在每次执行时返回不同的行

Pie*_*ant 4 oracle oracle-12c

我有一个查询,用于搜索我们网络中的子部门列表。当查询在没有任何过滤器的情况下执行时,它会在每次执行时返回不同数量的行

SELECT DISTINCT 
    t1.ZRESUBDIV,
    t1.SUBDIV_NAME
FROM M_STAGE_WP_PFUNCT_LOC t1
WHERE ROWNUM <= 200  -- normally a filter goes here
ORDER BY t1.SUBDIV_NAME
Run Code Online (Sandbox Code Playgroud)

执行 1

ZRESUBDIV SUBDIV_NAME                                                
------------ -------------------------------------- ---------------
262 亚历山大                                                  
400 艾伦沃特                                                  
第671章                                                    
第372章                                                        
277 比奇堡                                                   
200桥                                                      
第374章                                                     
543 中央比尤特                                               
第208章                                                     
第324章                                                     
340芝加哥                                                     
...

执行 2

ZRESUBDIV SUBDIV_NAME                                                
------------ -------------------------------------- ---------------
670 阿尔布雷达                                                     
262 亚历山大                                                  
400 艾伦沃特                                                  
第671章                                                    
第372章                                                        
277 比奇堡                                                   
604 黑脚                                                   
200桥                                                      
第607章                                                     
第354章                                                        
543 中央比尤特                                               
...

还有缺失的数据:细分巴吞鲁日虽然在数据中但从未出现过。

如果我删除 ROWNUM,所有数据都会正确返回。我需要保留 ROWNUM,因为查询支持 WHERE 子句,并在细分名称上使用过滤器。

这是什么原因?

Bal*_*app 10

ROWNUM之前评估过ORDER BY,这不是ROWNUM应该如何使用。要ROWNUM正确使用,请使用如下查询:

SELECT * FROM 
(
  SELECT DISTINCT 
      t1.ZRESUBDIV,
      t1.SUBDIV_NAME
  FROM M_STAGE_WP_PFUNCT_LOC t1
  ORDER BY t1.SUBDIV_NAME
)
WHERE ROWNUM <= 200;
Run Code Online (Sandbox Code Playgroud)

但这是旧的。由于您使用的是 12c,请使用以下命令:

SELECT DISTINCT 
    t1.ZRESUBDIV,
    t1.SUBDIV_NAME
FROM M_STAGE_WP_PFUNCT_LOC t1
ORDER BY t1.SUBDIV_NAME
FETCH FIRST 200 ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)


ype*_*eᵀᴹ 7

ROWNUM是做这种查询的错误方式。正如@Kris Johnston 在带有“cart and the horse”比喻的评论中所解释的那样:该WHERE子句在 之前执行ORDER BY,如果没有 ,您将无法保证结果的顺序ORDER BY,所以是的,每次运行都会产生不同的结果。

您可以改用ROW_NUMBER()和子查询:

SELECT
    t.ZRESUBDIV,
    t.SUBDIV_NAME
FROM
  ( SELECT 
        t1.ZRESUBDIV,
        t1.SUBDIV_NAME,
        ROW_NUMBER() OVER (ORDER BY t1.SUBDIV_NAME) AS RN
    FROM M_STAGE_WP_PFUNCT_LOC t1
    WHERE --- your filter goes here but NOT any ROWNUM
    GROUP BY
        t1.ZRESUBDIV,
        t1.SUBDIV_NAME
  ) t
WHERE
    t.RN <= 200
ORDER BY
    t.SUBDIV_NAME ;
Run Code Online (Sandbox Code Playgroud)

internalORDER BY定义将选择哪些行(因为前 200 行将具有从 1 到 200 的 row_numbers),而 externalORDER BY是可选的,仅对演示顺序有影响。

请注意,排序不是全部,即您可能有相同的行SUBDIV_NAME。如果您希望完全指定订单,您可以将它们更改ORDER BYORDER BY SUBDIV_NAME, BYZRESUBDIV(例如)。

@Balazs Papp 的回答中的其他 2 个查询也很好,如果不是更好的话。ROW_NUMBER()在实施之前,第一个可能被广泛使用,因为它适用于旧版本。第二个肯定是你能得到的最简洁的,只要你是 12c 版本。