In Oracle 11g, how to change the order of the results of a sql without "order by"? [closed] - sql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Now I have a very simple SQL:
select * from table A
I know the results will be sorted by "rowid"(I'm not very sure, I'm a freshman).
And Oracle will not guarantee the order of the results of a SQL without "order by".
Here's my question:
Once I've got results in such order: ....A...B....
Now I want the results in this order: ....B...A....
Just make B before A is OK.
How to do this?
Notice 1: This is an experiment. Please be patient to think about my question.
Notice 2: Do not change the primary key of any record, and do not use any DDL, and use the same SQL "select * from table A".
Notice 3:
create table A(id NUMBER(20) primary key, name VARCHAR2(30));
insert into A values(1,'one');
insert into A values(2,'two');
select * from A;
What I've tried : update, insert ,delete some records, which do not work.

Edit
Given this requirement:
Do not change the SQL select * from table A.
Change the table A to change the results order
the answer is a clear and definite: this is not possible.
(Keeping my initial answer as a reference)
"I know the results will be sorted by rowid" - no, they are not.
The rows will be returned in any order the database thinks is the most efficient.
There is no, absolutely no, guarantee that rows are returned in any specific order unless you specify an ORDER BY.
The ONLY way to get a specific order is to use an ORDER BY.
If you want 'B' to come before 'A' then simply do a descending order:
select *
from table_A
order by some_col DESC
You can put more logic into the ORDER BY operator by applying expressions or functions. If you e.g. want to list 'B' at the top and everything else after that in alphabetical order, you can do something like this:
select *
from table_a
order by
case
when some_col = 'B' then 0
else 1
end,
some_col

You keep trying to "clarify" your question. As best I can understand it, you're attempting to present a "puzzler" of some sort. But your puzzler is nonsensical. What I think you are missing is an understanding of "WHY" the rows are being returned in the order you inserted them. When you understand that, you'll have a better appreciation of what your question is actually asking, and why you won't be able to solve it.
If you
1) create a standard Oracle table "A" with PK ID and one (or more) other columns and
2) insert just a couple rows (e.g. less data than will fill a datablock),
3) do no subsequent indexing, moves, reorgs, compression, etc
then yes, all existing implementations of Oracle will resolve SELECT * FROM A by returning your two rows in the same order you inserted them.
This is because
1) current Oracle implementations will write new records to an empty datablock in the order they were received and
2) subsequent SELECT * FROM A, if there is no index which offers a better plan, will cause a full-table-scan. Since all of your data will be in a single datablock, and current Oracle implementations read data within a block sequentially, "SELECT * FROM A" will "stably" return rows in the order you inserted them.
In that context, your puzzler seems to be: can a person issue INSERT/UPDATE/DELETE statements against TABLE A such that current Oracle implementations will execute "SELECT * FROM TABLE A" and return your two rows in reverse order. Such a challenge is trivially (and really only) solved by, e.g., deleting your two rows and re-inserting them with the ID=2 row first and ID=1 row second. But your statement "Do not change the primary key of any record" indicates that deleting/re-inserting isn't an option. In which case, yes, you're asking for the impossible, even from a puzzling perspective: your challenge is to wave a magic wand at Oracle such that it will start reading rows within the same datafile from end-to-start.
ETA: You also disallowed DDL; otherwise, you could do an amusing hack like this to get the desired effect:
create table A(id NUMBER(5) primary key, name VARCHAR2(10))
partition by list (id)
(partition p1 values (2),
partition p2 values (1));
insert into A values(1,'one');
insert into A values(2,'two');
select * from a;
ID NAME
---- ---------
2 two
1 one

Only
ORDER BY
is there for the work. But you can do the required arrangement by making a simple function with the logic you want behind the format of the returned rows and use that function.

Related

Same query producing different results [duplicate]

This question already has answers here:
Order by not working when insert in temp table
(4 answers)
Closed 5 years ago.
Below is my query:
CREATE TABLE #TEMP(CID INT,PID INT,STAT VARCHAR(20),TIN DATETIME, TOUT DATETIME)
INSERT INTO #TEMP(CID,STAT,PID,TIN,TOUT)
SELECT DISTINCT CID,STST,PID,TIN,TOUT
FROM CVTBL
WHERE STAT = 'YES'
AND PID = '12'
ORDER BY CID DESC;
select * from #temp
drop table #temp
This is a very straight forward query. However everytime when I run the select * from #temp it produced different result sets but the total number of rows is the same. How does that work?
I'm going to elaborate on this as an answer,but both Veljko89 and tarheel have hit the nail on the head in the comments they made on the OP's question.
Data, in SQL Server, is stored in unordered HEAPS. Regardless of the order you INSERT the data, regardless of if you have a CLUSTERED INDEX or not, performing a SELECT statement without an ORDER BY has no guarenteed order. Period.
The only (yes that's right ONLY) way to guarentee the order of a result set is to (unsurprisingly) use the ORDER BY clause. If you omit that clause SQL Server will return the rows in whatever order it processed that rows, which could be any order at all. For small tables, yes, you are likely to get the same order, and if you have a CLUSTERED INDEX then that improves that possibility, but that's just it, it's a possibility.
Once you get to larger tables, and start introducing multiple cores processing the information, then the order will become more and more randomised; as with larger datasets the data that is read first is more likely to vary, and with multiple cores one may finish processing its data first, however, had data from "further" in the table.
So, in summary: Add an ORDER BY clause (so that each column has a unique set) to ensure your queries always return data in the same order.

What does * mean in sql?

For example, I know what SELECT * FROM example_table; means. However, I feel uncomfortable not knowing what each part of the code means.
The second part of a SQL query is the name of the column you want to retrieve for each record you are getting.
You can obviously retrieve multiple columns for each record, and (only if you want to retrieve all the columns) you can replace the list of them with *, which means "all columns".
So, in a SELECT statement, writing * is the same of listing all the columns the entity has.
Here you can find probably the best tutorial for SQL learning.
I am providing you answer by seperating each part of code.
SELECT == It orders the computer to include or select each content from the database name(table ) .
(*) == means all {till here code means include all from the database.}
FROM == It refers from where we have to select the data.
example_table == This is the name of the database from where we have to select data.
the overall meaning is :
include all data from the databse whose name is example_table.
thanks.
For a beginner knowing the follower concepts can be really useful,
SELECT refers to attributes that you want to have displayed in your final query result. There are different 'SELECT' statements such as 'SELECT DISTINCT' which returns only unique values (if there were duplicate values in the original query result)
FROM basically means from which table you want the data. There can be one or many tables listed under the 'FROM' statement.
WHERE means the condition you want to satisfy. You can also do things like ordering the list by using 'order by DESC' (no point using order by ASC as SQL orders values in ascending order after you use the order by clause).
Refer to W3schools for a better understanding.

Updating Table Records in a Batch and Auditing it

Consider this Table:
Table: ORDER
Columns: id, order_num, order_date, order_status
This table has 1 million records. I want to update the order_status to value of '5', for a bunch (about 10,000) of order_num's that i will be reading from a input text file.
My SQL could be:
(A) update ORDER set order_status=5 where order_num in ('34343', '34454', '454545',...)
OR
(B) update ORDER set order_status=5 where order_num='34343'
I can loop over this update several times until I have covered my 10,000 order updates.
(Also note that i have few Child Tables of ORDER like ORDER_ITEMS, where similar status must be updated and information audited)
My problem is here is:
How can i Audit this update in a separate ORDER_AUDIT Table:
Order_Num: 34343 - Updated Successfully
Order_Num: 34454 - Order Not Found
Order_Num: 454545 - Updated Successfully
Order_Num: 45457 - Order Not Found
If i go for batch update as in (A), I cannot Audit at Order Level.
If i go for Single Order at at time update as in (B), I will have to loop 10,000 times - that may be quite slow - but I can Audit at Order level in this case.
Is there any other way?
First of all, build an external table over your "input text file". That way you can run a simple single UPDATE statement:
update ORDER
set order_status=5
where order_num in ( select col1 from ext_table order by col1)
Neat and efficient. (Sorting the sub-query is optional: it may improve the performance of the update but the key point is, we can treat external tables like regular tables and use the full panoply of the SELECT syntax on them.) Find out more.
Secondly use the RETURNING clause to capture the hits.
update ORDER
set order_status=5
where order_num in ( select col1 from ext_table order by col1)
returning order_num bulk collect into l_nums;
l_nums in this context is a PL/SQL collection of type number. The RETURNING clause will give you all the ORDER_NUM values for updated rows only. Find out more.
If you declare the type for l_nums as a SQL nested table object you can use it in further SQL statements for your auditing:
insert into order_audit
select 'Order_Num: '||to_char(t.column_value)||' - Updated Succesfully'
from table ( l_nums ) t
/
insert into order_audit
select 'Order_Num: '||to_char(col1)||' - Order Not Found'
from ext_table
minus
select * from table ( l_nums )
/
Notes on performance:
You don't say how many of the rows you have in the input text file will match. Perhaps you don't know (actually on re-reading it's not clear whether 10,000 is the number of rows in the file or the number of matching rows). Pl/SQL collections use private session memory, so very large collections can blow the PGA. However, you should be able to cope with ten thousand NUMBER instances without blinching.
My solution does require you to read the external table twice. This shouldn't be a problem. And it will certainly be way faster than dynamically assembling one hundred IN clauses of a thousand numbers and looping over each.
Note that update is often the slowest bulk operation known to man. There are ways of speeding them up, but those methods can get quite involved. However, if this is something you'll want to do often and performance becomes a sticking point you should read this OraFAQ article.
Use MERGE. Firstly load data into a temporary table called ORDER_UPD_TMP with only one column id. You can do it using SQLDeveloper import feature. Then use MERGE in order to udpate your base table:
MERGE INTO ORDER b
USING (
SELECT order_id
FROM ORDER_UPD_TMP
) e
ON (b.id = e.id)
WHEN MATCHED THEN
UPDATE SET b.status = 5
You can also update with a different status when records don't match. Check the documentation for more details:
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm
I think the best way will be:
to import your file to the database first
then do few SQL UPDATE/INSERT queries in one transaction to update status for all orders and create audit records.

Is there a way to include a query that is non updateable in an UPDATE query? [duplicate]

This question already has an answer here:
Access SQL Update One Table In Join Based on Value in Same Table
(1 answer)
Closed 10 years ago.
For the following query:
UPDATE tempSpring_ASN AS t
SET t.RECORD_TYPE = (
SELECT TOP 1 RECORD_TYPE
FROM (
SELECT "A" AS RECORD_TYPE
FROM TABLE5
UNION ALL
SELECT "B" AS RECORD_TYPE
FROM TABLE5
)
);
I'm getting, "Operation must use an updateable query." I don't understand. I'm not trying to update a union query. I'm just trying to update an otherwise updatable recordset with the output (single value) of a union query.
(The solution provided at Access SQL Update One Table In Join Based on Value in Same Table (which is also provided below) does not work for this situation, contrary to what is indicated on the top of this page.)
This question is a reference to a previous question, data and code examples posted here:
Access SQL Update One Table In Join Based on Value in Same Table
Hi AYS,
In Access, an Update query needs to be run on a table.
As a UNION query is a combination of multiple sets of records, the result set is no longer a table, and cannot be the object of an Update query as the records in the result set are no longer uniquely identified with any one particular table (even if they theoretically could be). Access is hard-coded to treat every UNION query as read-only, which makes sense when there are multiple underlying tables. There are a number of other conditions (such as a sub-query in the SELECT statement) that also trigger this condition.
Think if it this way: if you were not using TOP 1 and your UNION query returned multiple results, how would JET know which result to apply to the unique record in your table? As such, JET treats all such cases the same.
Unfortunately, this is the case even when all of the data is being derived from the same table. In this case, it is likely that the JET optimizer is simply not smart enough to realize that this is the case and re-phrase the query in a manner that does not use UNION.
In this case, you can still get what you want by re-stating your query in such a way that everything references your base table. For example, you can use the following as a SELECT query to get the PO_NUM value of the previous SHP_CUSTOM_5 record:
SELECT
t1.SHP_CUSTOM_5
, t1.PO_NUM
, t1.SHP_CUSTOM_5 -1 AS PREV_RECORD
, (SELECT
t2.PO_NUM
FROM
tempSpring_ASN As t2
WHERE
t2.SHP_CUSTOM_5 = (t1.SHP_CUSTOM_5 -1)
) AS PREV_PO
FROM
tempSpring_ASN AS t1
;
You can then phrase this as an Update query as follows in order to perform the "LIN" updates:
UPDATE
tempSpring_ASN AS t1
SET
t1.RECORD_TYPE = "LIN"
WHERE
t1.PO_NUM=
(
SELECT
t2.PO_NUM
FROM
tempSpring_ASN As t2
WHERE
t2.SHP_CUSTOM_5 = (t1.SHP_CUSTOM_5 -1)
)
;
This code was successful in the tests I ran with dummy data.
Regarding your "HDR" updates, your are really performing two separate updates.
1) If the PO_NUM matches the previous record's PO_NUM, set RECORD_TYPE to "LIN"
2) If it is the first record, set RECORD_TYPE to "HDR"
It is not clear to me why there would be a benefit to performing these actions within one query. I would recommend performing the HDR update using the "TOP 1" by SHP_CUSTOM_5 method you used in your original SELECT query example, as this will be a relatively simple UPDATE query. It is possible to use IIF() within an Update query, but I do not know what additional benefit you would gain from the additional time and complexity that would be required (it would most likely only be much less readable).
Best of luck!

SQL - renumbering a sequential column to be sequential again after deletion

I've researched and realize I have a unique situation.
First off, I am not allowed to post images yet to the board since I'm a new user, so see appropriate links below
I have multiple tables where a column (not always the identifier column) is sequentially numbered and shouldn't have any breaks in the numbering. My goal is to make sure this stays true.
Down and Dirty
We have an 'Event' table where we randomly select a percentage of the rows and insert the rows into table 'Results'. The "ID" column from the 'Results' is passed to a bunch of delete queries.
This more or less ensures that there are missing rows in several tables.
My problem:
Figuring out an sql query that will renumber the column I specify. I prefer to not drop the column.
Example delete query:
delete ItemVoid
from ItemTicket
join ItemVoid
on ItemTicket.item_ticket_id = itemvoid.item_ticket_id
where itemticket.ID in (select ID
from results)
Example Tables Before:
Example Tables After:
As you can see 2 rows were delete from both tables based on the ID column. So now I gotta figure out how to renumber the item_ticket_id and the item_void_id columns where the the higher number decreases to the missing value, and the next highest one decreases, etc. Problem #2, if the item_ticket_id changes in order to be sequential in ItemTickets, then
it has to update that change in ItemVoid's item_ticket_id.
I appreciate any advice you can give on this.
(answering an old question as it's the first search result when I was looking this up)
(MS T-SQL)
To resequence an ID column (not an Identity one) that has gaps,
can be performed using only a simple CTE with a row_number() to generate a new sequence.
The UPDATE works via the CTE 'virtual table' without any extra problems, actually updating the underlying original table.
Don't worry about the ID fields clashing during the update, if you wonder what happens when ID's are set that already exist, it
doesn't suffer that problem - the original sequence is changed to the new sequence in one go.
WITH NewSequence AS
(
SELECT
ID,
ROW_NUMBER() OVER (ORDER BY ID) as ID_New
FROM YourTable
)
UPDATE NewSequence SET ID = ID_New;
Since you are looking for advice on this, my advice is you need to redesign this as I see a big flaw in your design.
Instead of deleting the records and then going through the hassle of renumbering the remaining records, use a bit flag that will mark the records as Inactive. Then when you are querying the records, just include a WHERE clause to only include the records are that active:
SELECT *
FROM yourTable
WHERE Inactive = 0
Then you never have to worry about re-numbering the records. This also gives you the ability to go back and see the records that would have been deleted and you do not lose the history.
If you really want to delete the records and renumber them then you can perform this task the following way:
create a new table
Insert your original data into your new table using the new numbers
drop your old table
rename your new table with the corrected numbers
As you can see there would be a lot of steps involved in re-numbering the records. You are creating much more work this way when you could just perform an UPDATE of the bit flag.
You would change your DELETE query to something similar to this:
UPDATE ItemVoid
SET InActive = 1
FROM ItemVoid
JOIN ItemTicket
on ItemVoid.item_ticket_id = ItemTicket.item_ticket_id
WHERE ItemTicket.ID IN (select ID from results)
The bit flag is much easier and that would be the method that I would recommend.
The function that you are looking for is a window function. In standard SQL (SQL Server, MySQL), the function is row_number(). You use it as follows:
select row_number() over (partition by <col>)
from <table>
In order to use this in your case, you would delete the rows from the table, then use a with statement to recalculate the row numbers, and then assign them using an update. For transactional integrity, you might wrap the delete and update into a single transaction.
Oracle supports similar functionality, but the syntax is a bit different. Oracle calls these functions analytic functions and they support a richer set of operations on them.
I would strongly caution you from using cursors, since these have lousy performance. Of course, this will not work on an identity column, since such a column cannot be modified.