Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SELECT * FROM TABLE(pipelined function): can I be sure of the order of the rows in the result?

In the following example, will I always get “1, 2”, or is it possible to get “2, 1” and can you tell me where in the documentation you see that guarantee if it exists?

If the answer is yes, it means that without ORDER BY nor ORDER SIBLINGS there is a way to be sure of the result set order in a SELECT statement.

CREATE TYPE temp_row IS OBJECT(x number);
/

CREATE TYPE temp_table IS TABLE OF temp_row;
/

CREATE FUNCTION temp_func
RETURN temp_table PIPELINED
IS
BEGIN
    PIPE ROW(temp_row(1));
    PIPE ROW(temp_row(2));
END;
/

SELECT * FROM table(temp_func());

Thank you.

like image 814
Benoit Avatar asked May 23 '13 11:05

Benoit


Video Answer


2 Answers

I don't think that there's anywhere in the documentation that guarantees the order that data will be returned in.

There's an old Tom Kyte thread from 2003 (so might be out of date) which states that relying on the implicit order would not be advisable, for the same reasons as you would not rely on the order in ordinary SQL.

1st: is the order of rows returned from the table function within a SQL statement the exact same order in which the entries were "piped" into the internal collection (so that no order by clause is needed)?

...

Followup May 18, 2003 - 10am UTC:

1) maybe, maybe not, I would not count on it. You should not count on the order of rows in a result set without having an order by. If you join or do something more complex then simply "select * from table( f(x) )", the rows could well come back in some other order.

empirically -- they appear to come back as they are piped. I do not believe it is documented that this is so.

In fact, collections of type NESTED TABLE are documented to explicitly not have the ability to preserve order.

To be safe, you should do as you always would in a query, state an explicit ORDER BY, if you want the query results ordered.

Having said that I've taken your function and run 10 million iterations, to check whether the implicit order was ever broken; it wasn't.

SQL> begin
  2    for i in 1 .. 10000000 loop
  3      for j in ( SELECT a.*, rownum as rnum FROM table(temp_func()) a ) loop
  4
  5         if j.x <> j.rnum then
  6            raise_application_error(-20000,'It broke');
  7         end if;
  8      end loop;
  9    end loop;
 10  end;
 11  /

PL/SQL procedure successfully completed.
like image 67
Ben Avatar answered Sep 28 '22 03:09

Ben


This procedural logic works differently to table-based queries. The reason that you cannot rely on orders in a select from a table is that you cannot rely on the order in which the RDBMS will identify rows as part of the required set. This is partly because of execution plans changing, and partly because there are very few situations in which the physical order of rows in a table is predictable.

However here you are selecting from a function that does guarantee the order in which the rows are emitted from the function. In the absence of joins, aggregations, or just about anything else (ie. for a straight "select ... from table(function)") I would be pretty certain that the row order is deterministic.

That advice does not apply where there is a table involved unless there is an explicit order-by, so if you load your pl/sql collection from a query that does not use an order-by then of course the order of rows in the collection is not deterministic.

like image 41
David Aldridge Avatar answered Sep 28 '22 03:09

David Aldridge