Oracle SQL -Query result was not ordered based on Index - oracle

I have a table with 5 columns,
column1, column2, column3, column4, column5
of which column1, column2 and column3 constitute 'primary key'
temp_table
Column1 Column2 Column3 Column4 Column5
2 209 Raj Kumar K
2 27 Arvind Ram R
2 227 Mahesh Kumar M
whenever i query the table, the results would be ordered by the primary key columns even if i do not give order by in the query.
Select Column1, Column2, Column3 from temp_table;
every time i run this query i do get the result as,
Column1 Column2 Column3
2 27 Arvind
2 209 Raj
2 227 Mahesh
But at one particular instance only, the query result was not ordered by primary key columns.
The result was like below,
Column1 Column2 Column3
2 209 Raj
2 27 Arvind
2 227 Mahesh
Can somebody help to find the reason why.

even if i do not give order by in the query
You should always use an ORDER BY clause if you expect to have reproducible and deterministic ordering in a result set. You should not assume any inherent order in a SQL table, as tables are modeled after (unordered) sets. As to why the ordering changed in that one instance, perhaps the way the underlying data was being stored, or maybe cached, was different for that one instance. But in any case, use you should always use ORDER BY if you expect a certain order.

You have to use ORDER BY like :
Select Column1, Column2, Column3
from temp_table
order by Column?;
And choose the column you want. You can also have DESC and ASC in the end like :
Select Column1, Column2, Column3
from temp_table
order by Column? ASC;
For ordinates decreasing or increasing.

Related

Select TOP N and BOTTOM N

Trying to fetch top n bottom n rows. Though it gives me result but, it takes lot of time. I believe it scans table twice.
Code used:
WITH TI AS
(SELECT * FROM
(SELECT
Column1,
Column2,
Colmn3
FROM TABLE
ORDER BY DESC
)
WHERE ROWNUM<=5),
T2 AS
(SELECT * FROM
(SELECT
Column1,
Column2,
Colmn3
FROM TABLE
ORDER BY ASC
)
WHERE ROWNUM<=5)
SELECT * FROM T1
UNION ALL
SELECT * FROM T2
How can i fetch this in more faster way??
Considering that tables are updated regularly.
The best way to solve this problem depends in part on your Oracle version. Here is a very simple (and, I suspect, very efficient) solution using the match_recognize clause, added in version 12.1.
I illustrate it using the EMPLOYEES table in the standard HR schema, ordering by SALARY. The only trick here is to select the top and bottom five rows, and to ignore everything in between; that (the "ignoring") is what the {- ... -} operator does in the pattern sub-clause.
select employee_id, first_name, last_name, salary
from hr.employees
match_recognize(
order by salary desc
all rows per match
pattern ( a{5} {- a* -} a{5} )
define a as 0 = 0 -- For reasons known only to Oracle, DEFINE is required.
);
EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY
----------- -------------------- ------------------------- ----------
100 Steven King 24000
101 Neena Kochhar 17000
102 Lex De Haan 17000
145 John Russell 14000
146 Karen Partners 13500
135 Ki Gee 2400
127 James Landry 2400
136 Hazel Philtanker 2200
128 Steven Markle 2200
132 TJ Olson 2100
You can combine into a single query and a single pass over the table using analytic functions, generating two pseudocolumns in this case:
select column1, column2, column3,
row_number() over (order by column1 desc) rn_desc,
row_number() over (order by column1 asc) rn_asc
from your_table;
and then filtering using that query as an inline view (or CTE):
select column1, column2, column3
from (
select column1, column2, column3,
row_number() over (order by column1 desc) as rn_desc,
row_number() over (order by column1 asc) as rn_asc
from your_table
)
where rn_desc <=5
or rn_asc <= 5;
I've assumed your ordering is on column1, and picked your_table as a table name as you didn't include that either, so change as appropriate. Depending on how you want to handle ties, you might want to use the rank() or dense_rank() functions instead.
From #mathguy's comment, this may well perform better:
select column1, column2, column3
from (
select column1, column2, column3,
row_number() over (order by column1 desc) as rn,
count(*) over () as cnt
from your_table
)
where rn <=5
or cnt - rn < 5;

Check for != values when column contains records with NULLs

I have a number of tables that mix 'real' values with nulls in columns. From exerience, issuing a SELECT against these that looks like:
SELECT column1, column2, column3 FROM mytable WHERE column1 != 'a value';
...doesn't return the records I expect. In the current table I am working on, this returns an empty recordset, even though I know I have records in the table with NULLs in column1, and other records in the table that have the value I am "!="ing in column1. I am expecting, in this case, to see the records with NULLs in column1 (and, of course, anything else if there were other not 'a value' values in column1.
Experimenting with NVL in the WHERE clause doesn't seem to give me anything different:
SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '') != 'a value';
...is also returning an empty recordset.
Using 'IS NULL' will technically give me the correct recordset in my current example, but of course if any records change to something like 'another value' in column1, then IS NULL will exclude those.
NULL can't be compared in the same way that other values can be. You must use IS NULL. If you want to include NULL values, add an OR to the WHERE clause:
SELECT column1, column2, column3 FROM mytable WHERE column1 != 'a value' OR column1 IS NULL
The query doesn't work because SQL handles equality checks (!=) different from checking if null (IS NULL).
What you could do here is something like:
SELECT column1, column2, column3
FROM mytable
WHERE column1 != 'a value' OR column1 is null;
See Not equal <> != operator on NULL.
What you were trying was correct. You just need change it a little. see below-
SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '0') != 'a value';
Instead of empty string, pass any character in NVL's second argument.
"Experimenting with NVL in the WHERE clause doesn't seem to give me anything different"
That's true:
SQL> select * from mytable;
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
a value 1 25-JUL-17
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL> SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '') != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
SQL>
This is because your experiment didn't go far enough. For historical reasons Oracle treats an empty string as null so your nvl() statement effectively just subs one null for another. But if you had used a proper value in your call you would have got the result you wanted:
SQL> SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, 'meh') != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL>
The alternative approach is to explicitly test for NULL and test for the excluding value...
SQL> SELECT column1, column2, column3 FROM mytable
2 where column1 is null or column1 != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL>
The second approach is probably more orthodox.
1) Undocumented Oracle function SYS_OP_MAP_NONNULL. (It exists from oracle10)
with abc as ( select 'a value' as col1 from dual
union all
select '' as col1 from dual)
select * from abc
where SYS_OP_MAP_NONNULL(col1) != SYS_OP_MAP_NONNULL('a value')
;
2) LNNVL - Check table in the documentation for clarification.
with abc as ( select 'a value' as col1 from dual
union all
select '' as col1 from dual)
select * from abc
where lnnvl( col1 = 'a value');
;

in oracle select query how to add a number column increment by 2 starting from 1

i need to write a oracle select query where i need a additional column which increment by 2 starting from 1.
Example:
column1 column2
amit 1
siva 3
pyll 5
here from oracle table i can get only column1. but in query i have to generate column2. So my issue is dynamically get a column like rownum() and increment it by 2. is there any way to get such result. in mysql we can use session variables inside a query. i expect a similar kind of solution in oracle. but i couldn't find a simple query to generate such numbers.
You know you have rownum available, but take a step back. You're starting with the contiguous sequence 1,2,3,4,5,6,... and you want to generate a sequence of odd numbers 1,3,5,7,9,11,.... So you need to figure out an algorithm that will convert one to the other.
If you say your starting number is n then you want to generate m where m=(2*n)-1.
You can use rownum (or row_number(), etc.) to generate your n values:
select column1, rownum as n
from your_table;
And you can then apply that algorithm:
select column1, (2*rownum)-1 as column2
from your_table;
COLUMN1 COLUMN2
------- ----------
amit 1
siva 3
pyll 5
jane 7
john 9
anna 11
...
With this simple approach the column2 values are not in the same order as the column1 values. You can either use row_number() or rank() instead, with a suitable order by clause; or use a subquery which does the ordering and apply rownum (and this algorithm) outside that:
select column1, (2*rownum)-1 as column2
from (
select column1
from your_name
order by column1
);
or some other variation, depending on the result you want to end up with.

return null if no rows found oracle query with IN clause

I have a table with three columns.
I query that table with IN clause.
select column1 from table1 where column1 in (1,2,3) order by column2, column3
The table1 contains only values 1 and 2 in column1. I want to return the not available value also in my result, and that should be sorted in the bottom.
example data
column1 column 2 column 3
1 100 11
2 101 50
output, the not available values should be in the last.
column1 column 2 column 3
1 100 11
2 101 50
3 null null
I tried with subquery with NVL, like select nvl((select.. in(1,2,3)),null) from dual, due to IN Clause, I am getting single row subquery returns more than one row issue, which is expected.
Also tried with the union but nothing works. Great if any help. Thanks
I think you can do it with a union all:
select column1 from table1 where column1 in (1,2,3) order by column2, column3
union all
select null from table1 where column1 not in (1,2,3) order by column2, column3
If you can't take 1,2,3 values from another table you can try with:
with t1 as (
select col1,col2,col3
from tab1
where cod_flusso in ('1','2','3')),
t2 as (
select '1' as col1,null,null
from dual
union
select '2',null,null
from dual
union
select '3',null,null
from dual)
select t2.col1,col2,col3
from t2
left outer join t1
on t1.col1= t2.col1
It's better if you can store 1,2,3 values in a second table, then use left outer join.

I want to return data from duplicate rows SQL Query

I want to return data from duplicative rows
SELECT column1, column2 FROM table1
COLUMN1 COLUMN2
------- -------
CA 1
CB 2
CB 3
CC 4
CD 5
CE 6
CE 7
CE 8
CF 9
I want to return rows for 'CB' and CE. Here CB and CE has more than 1 row.
I'd code this as follows:
SELECT column1, column2 FROM table1 where column1 in ("CB", "CE")
Try this out - this query first finds out those items in column1 who appear multiple time and then extract their information.
select * from table1
where column1 in (
select column1
from table1
group by column1
having count(*) > 1
)
If you are only interested in knowing the values in column1, you could just run:
select column1
from table1
group by column1
having count(*) > 1
You Can try out this code. Basically the Query is in MySQL but you can use the same logic in Oracle Database. Here the inner subquery will find out the columns which is grouped by column1 and will return a column having a count greater than 1. The Outer query will display the rows of the column fetched by the inner query.Here I have created a table with the table name as name
SQL fiddle Added for your reference SQLCODE
select * from name where column1 in(select column1 from name
group by column1
having count(*)>1);

Resources