Para que el resultado de una consulta SQL esté ordenado, la única cláusula válida es ORDER BY.
Aquí no hay más.
A lo largo de las distintas versiones de Oracle, ciertas operaciones parecía que devolvían filas ordenadas fruto de realizar internamente operaciones que ordenaban el subconjunto de filas, pero Oracle únicamente garantiza la devolución ordenada de las filas cuando se establece ORDER BY como criterio de ordenación.
Es el estándar, y la única cláusula que garantiza la ordenación.
He repetido estas frases como un mantra miles de veces.
Cualquier otra forma de obtener los datos ordenados es:
- Una casualidad.
- Una ilusión.
- Una circunstancia temporal.
- Una combinación de las anteriores.
Los ejemplos que mostraré a continuación, de resultados ordenados sin cláusula ORDER BY en el comando SELECT, son fruto de la imaginación…
MITO #1 – Cuando las filas se insertan en un orden determinado.
SQL> create table objetos as select object_id, object_name, object_type 2 from dba_objects order by object_id; Table created. SQL> select * from objetos where rownum<10; OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------- -------------------- ------------------- 2 C_OBJ# CLUSTER 3 I_OBJ# INDEX 4 TAB$ TABLE 5 CLU$ TABLE 6 C_TS# CLUSTER 7 I_TS# INDEX 8 C_FILE#_BLOCK# CLUSTER 9 I_FILE#_BLOCK# INDEX 10 C_USER# CLUSTER 9 rows selected.
MITO #2 – Si las filas se recuperan a partir de usar un índice.
SQL> create table objetos_indice as select object_id, object_name, object_type 2 from dba_objects; Table created. SQL> create index idx_object_id on objetos_indice (object_id); Index created. SQL> select * from objetos_indice where object_id between 11256 and 11260; OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------- -------------------- ------------------- 11256 ALL_APPLY SYNONYM 11257 DBA_APPLY_PARAMETERS VIEW 11258 DBA_APPLY_PARAMETERS SYNONYM 11259 ALL_APPLY_PARAMETERS VIEW 11260 ALL_APPLY_PARAMETERS SYNONYM
MITO #3 – Si se trata de una tabla IOT.
SQL> create table objetos_iot 2 (object_id, object_name, object_type, 3 constraint pk_objetos_iot primary key (object_id)) 4 organization index 5 as select object_id, object_name, object_type 6 from dba_objects; Table created. SQL> select * from objetos_iot where object_id between 11256 and 11265; OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------- ------------------------------ ------------------- 11256 ALL_APPLY SYNONYM 11257 DBA_APPLY_PARAMETERS VIEW 11258 DBA_APPLY_PARAMETERS SYNONYM 11259 ALL_APPLY_PARAMETERS VIEW 11260 ALL_APPLY_PARAMETERS SYNONYM 11261 _DBA_APPLY_SOURCE_SCHEMA VIEW 11262 _DBA_APPLY_SOURCE_OBJ VIEW 11263 DBA_APPLY_INSTANTIATED_OBJECTS VIEW 11264 DBA_APPLY_INSTANTIATED_OBJECTS SYNONYM 11265 ALL_APPLY_INSTANTIATED_OBJECTS VIEW 10 rows selected.
MITO #4 – Si la tabla está construída sobre un segmento cluster.
SQL> create cluster clu_objetos (object_id number) tablespace test; Cluster created. SQL> create index idx_cluster_objetos on cluster clu_objetos; Index created. SQL> create table padre_objeto (id number constraint pk_objeto primary key) cluster clu_objetos(id); Table created. SQL> insert into padre_objeto values (1); 1 row created. SQL> insert into padre_objeto values (2); 1 row created. SQL> insert into padre_objeto values (3); 1 row created. SQL> insert into padre_objeto values (4); 1 row created. SQL> insert into padre_objeto values (5); 1 row created. SQL> insert into padre_objeto values (6); 1 row created. SQL> create table hijo_objeto (id number constraint fk_objeto_padre references padre_objeto(id)) cluster clu_objetos(id); Table created. SQL> insert into hijo_objeto values (3); 1 row created. SQL> insert into hijo_objeto values (6); 1 row created. SQL> insert into hijo_objeto values (5); 1 row created. SQL> insert into hijo_objeto values (2); 1 row created. SQL> select * from hijo_objeto; ID ---------- 2 3 5 6
MITO #5 – Si la sentencia utiliza la cláusula DISTINCT.
SQL> create table test_orden (texto varchar2(50)); Table created. SQL> insert into test_orden values ('PPPPP'); 1 row created. SQL> insert into test_orden values ('FFFFF'); 1 row created. SQL> insert into test_orden values ('ZZZZZ'); 1 row created. SQL> insert into test_orden values ('AAAAA'); 1 row created. SQL> select texto from test_orden; TEXTO -------------------------------------------------- PPPPP FFFFF ZZZZZ AAAAA SQL> select distinct texto from test_orden; TEXTO -------------------------------------------------- AAAAA FFFFF PPPPP ZZZZZ
MITO #6 – Si la sentencia utiliza la cláusula GROUP BY.
SQL> select texto from test_orden; TEXTO -------------------------------------------------- PPPPP FFFFF ZZZZZ AAAAA SQL> select texto from test_orden group by texto; TEXTO -------------------------------------------------- AAAAA FFFFF PPPPP ZZZZZ
MITO #7 – Si la consulta resuelve una join haciendo un MERGE JOIN.
SQL> create table test_orden2 as select * from test_orden; Table created. SQL> select /*+USE_MERGE(t,t2) */ t.texto 2 from test_orden t, test_orden2 t2 3 where t.texto=t2.texto; TEXTO -------------------------------------------------- AAAAA FFFFF PPPPP ZZZZZ
Lo mejor es intentar olvidar estos ejemplos.
Aunque parezcan resultados ordenados, en cualquier momento podrían no serlo. Quizás habrá tramos ordenados, quizás aparentemente todo el subconjunto de filas parezca ordenado, o incluso pueda estarlo.
Son mitos, verdades que quizás algún tiempo fueron ciertas. Funcionalidades (como la tradicional forma de hacer GROUP BY) que sí ordenaban las filas, pero en futuras implementaciones se sustituyó por un HASH GROUP BY, en el que no era necesaria más la ordenación alfabética.
Quizás una query deje de obtener los datos a través de un determinado índice.
Todo es una ilusión.
Todas estas ordenaciones casuales, sin uso de la cláusula ORDER BY, son sólo fruto de la imaginación…