On Oracle 10g we need to insert records from a view into a table to support a dumb client application that does not have sort or ORDER options itself. Is there any way to control the order in which our INSERT statement adds records to the destination table?
-
Why do you need that? Is there some trigger that does something on insert? – zendar Aug 27 '09 at 09:54
-
Related to http://stackoverflow.com/questions/33841234/oracle-insert-select-with-order-by/33843721 – vapcguy Jul 20 '16 at 21:00
-
@zendar If it's like what I needed to do with a Countries table, one might have records that will be bound to a dropdown or listbox on a web page, and desire them to all be in alphabetical order by name, rather than numeric order by ID, and have new records that were added as an afterthought or due to current events and become out of order, requiring re-coding of pages to have sorted dropdowns/listboxes, when you can just fix it in the database, instead. – vapcguy Jul 20 '16 at 21:05
-
@vapcguy read the first line of the selected answer - without an "ORDER BY" you can't know in what order Oracle will return records even if you insert them in sorted order. The answer is seven years old, and it's still valid. – zendar Jul 22 '16 at 23:45
-
@zendar "You can't know in what order Oracle will return records even if you insert them in sorted order" -- B.S. How about actually trying my answer I posted below. Were you the downvoter? I proved I could do it. Yes, `ORDER BY` doesn't get enforced on a normal `INSERT`. Add the `/*+APPEND*/` hint from the accepted answer (which he dismissed, which is why I voted his down and added my own example, where it worked) and *voilà*, it works! It's why `ORDER BY` exists in the first place - if you append the rows in the order they are found, this is how you control your insertions. – vapcguy Jul 25 '16 at 15:09
-
@zendar And why he dismissed it was because of "any DML or concurrent activity...might produce a different physical organization". While possibly true, when are you ever going to be stupid enough to do that and wreck your own code by doing "concurrent activity"?! That's why I don't do concurrent operations and have a `COMMIT` statement in my code, so that doesn't happen! – vapcguy Jul 25 '16 at 15:14
5 Answers
You can not reliably control in what order Oracle retrieve the row of a table without an ORDER BY
.
Furthermore, without the /*+APPEND*/
hint, Oracle will store the rows physically in a heap table where there is room, which may not be at the end of the table ! You may think Oracle inserts them sequentially but any DML or concurrent activity (2+ sessions inserting) might produce a different physical organization.
You could use an INDEX ORGANIZED table to store the rows in the order of the PK. Most simple queries thereafter on that table will produce a sorted set of rows. This would not however guarantee that oracle will select the rows in that order if you don't specify an ORDER BY (depending on the query and the access path, the rows may come in any order).
You could also use a view with an order by, this is probably your best bet if you can't touch the application (rename the table, create a view with the name of the table, let the application think it queries the table). I don't know if it is feasible in your case.

- 66,725
- 9
- 119
- 171
-
2+1 Creating a view should give the desired result, and also avoids duplicating data. In fact OP mentions that they are already using a view, so maybe just adding an ORDER BY to that is sufficient. – Todd Owen Aug 27 '09 at 11:27
-
2"you can not reliably control in what order Oracle stores the rows physically in a heap table" ... not entirely true I think. A direct path insert would preserve the physical order within extents, hence it can be used to improve data segment compression. Something of a specialised case though, and of course select order by is not at all guaranteed. – David Aldridge Sep 01 '09 at 12:50
-
-1 Should have said how to use the `/*+APPEND*/` hint, not just alluded to it, then dismissed it. This is actually the answer of how to do it! Worked fine for me! – vapcguy Jul 20 '16 at 17:07
Unless you specify an ORDER BY, you can never guarantee the order in which Oracle will return rows from a SELECT

- 30,012
- 11
- 69
- 93
Just use an ORDER BY. Something like
INSERT INTO table
(
SELECT
column1, column2
FROM
view
ORDER BY
column2
)
EDIT, this won't work actually. You could create a temporary view with the rows in the appropriate order, then do the insert.

- 123
- 1
- 3
- 8
-
1You don't have to control the insert... See @Vincent's answer. And even if you insert them "ordered by", the select without ORDER BY will fail(sooner or later), the best in this situation is the ordered by view... – Svetlozar Angelov Aug 27 '09 at 10:06
Your main problem, that of your application not adding an ORDER BY to its query, might possibly be solved by the use of an index on the column(s) you wish to order by, then use a stored outline to cause the query to use the index to access the table.
You'd have to test to see if this will work or not - be aware that it is possibly not enough to just add an INDEX() hint because the optimiser may find a way to honour the hint while not accessing the index in the right order; and if the query joins to other tables the ordering might be lost anyway.

- 59,135
- 14
- 106
- 158
YES, there IS a way to control your order. I found through experience where I had a table of Countries, we'll call it OLD_COUNTRIES
, that looked like this:
-----------------------------------
| ID | CODE | NAME |
-----------------------------------
|112099 | AF | Afghanistan |
|112100 | AA | Albania |
|... | .. | ... |
|112358 | ZB | Zimbabwe |
|112359 | AZ | Azores Islands |
|... | .. | ... |
-----------------------------------
Where I wanted the items that were added after the main list of countries (like the Azores and other islands that were added later) to actually appear in alphabetical order with the rest of the countries when I inserted them into a new table:
CREATE TABLE MYAPP.COUNTRIES
(
ID NUMBER(*, 0)
, CODE NVARCHAR2(20)
, NAME NVARCHAR2(250)
);
I then ran this to make it work:
INSERT /*+ append */ INTO MYAPP.COUNTRIES (ID, CODE, NAME)
SELECT ID, CODE, NAME FROM MYAPP.OLD_COUNTRIES_TABLE ORDER BY NAME ASC;
COMMIT;
And my new COUNTRIES
table came through alphabetized by name just fine.
NOTE: COMMIT
is required or you'll get the error: ORA-12838: cannot read/modify an object after modifying it in parallel
when you try to open the table to look at it in Oracle SQL Developer.
NOTE: If you don't use /*+ append */
, it will not insert in the order you specify - it will ignore ORDER BY
. And I know that it used my ORDER BY
when I used /*+ append */
and not just defaulted to a primary key on the old or new tables because neither had primary keys.
CAVEAT: According to the accepted answer's author, the append hint, as with "any DML or concurrent activity...might produce a different physical organization". While possibly true, don't do any concurrent operations during this and have a COMMIT
statement in your code where I do, so that doesn't happen!

- 7,097
- 1
- 56
- 52
-
With appreciation to those that either upvoted on their own or reversed a downvote-wanted to note-I've gotten some flack before that this doesn't work, but my example proves it does. If you want to advocate the possibility of concurrent operations wrecking it, that's why I've added how to avoid that (pretty easy to do, by the way) as a caveat, so please read my whole answer before commenting/voting. Also, being a NEW table that is being created, no one should even be using this table. Existing data being copied, maybe another story, but that's why we have maintenance windows. Thanks. – vapcguy Feb 24 '17 at 18:20
-
. . A demonstration that code works once is not a guarantee that it always works. That would be like saying that because `2 + 2` is `4`, adding any integer to itself is always `4`. – Gordon Linoff Mar 21 '19 at 17:39
-
@GordonLinoff Yes, but given that the conditions I set above are nearly always going to be the same (always "2" in your example and not "3", etc.), it should nearly always work. The "nearly always" caveat allows for those scenarios when people are using "3" when they should be using "2": ex. you can't run scripts into tables as they are being modified & expect perfect results. You can't run scripts on source tables to copy data if people are injecting source data into them. These kinds of things should go without saying. Lock things down or create copies, then replace with the copies you make. – vapcguy Mar 22 '19 at 20:25