This question already has an answer here:
Oracle get DISTINCT numeric with a CLOB in the query
(1 answer)
Closed 8 years ago.
Refer to this question.
I am interested in selecting a DISTINCT NUMERIC from EVENTLOG that has an accompanying CLOB from EVENT_INFO_DETAIL that is not intended to be a DISTINCT selection.
In other words, I am interested in selecting a DISTINCT EVENTID_NBR because of the presence of multiple of the same number and to also see the CLOB associated with that DISTINCT EVENTID_NBR. I am NOT trying to select a DISTINCT CLOB in any way. How might I go about doing this?
For example, a result set could look like the following:
EVENID_NBR INPUT_ARGS (BYTE SIZE)
143 4096
143 3284
143 2162
143 2222
143 1024
I would want only one EVENTID_NBR because I need a representative sample in my result set but I also need the CLOB selected along with that DISTINCT EVENTID_NBR.
Is there a way to select just the first ROWID of each EVENTID_NBR that also include the associated CLOB?
Should I select a DISTINCT EVENTID_NBR and then try to find the CLOB associated with the EVENTID_NBR I have chosen?
This is typically done with a window function:
select evenid_nbr,
input_args
from (
select evenid_nbr,
input_args,
row_number() over (partition by evenid_nbr order by rowid) as rn
from event_info_detail
) t
where rn = 1
By changing the order by part you can adjust which evenid_nbr gets returned.
Related
I have a below query in Oracle having duplicate rows, where file_data is a BLOB column.
SELECT attachsysfilename, file_seq, version, file_size, lastupddttm, lastupdoprid, file_data
from PS_LP_EX_FILEATTCH
I want to apply distinct clause on top of it to get unique records. But unable to do so because of BLOB column.
Can someone please help in this regards?
How can I use the Scalar subquery on file_data column to get the DISTINCT records from the table?
assuming you have a primaru key for the PS_LP_EX_FILEATTCH table's row you could rey using subquery for an aggreagted result of the related primary key
select t.*, ps.file_data
from (
SELECT min(pk) my_id
attachsysfilename
,file_seq
,version
,file_size
,lastupddttm
,lastupdoprid
from PS_LP_EX_FILEATTCH
group by attachsysfilename
,file_seq
,version
,file_size
,lastupddttm
,lastupdoprid
) t
inner join PS_LP_EX_FILEATTCH ps ON t.my_id = ps.pk
You could use a hash of the BLOB values and group by the hash along with all the other (the non-BLOB) columns, select one pk (or rowid, see discussion below) from each group, for example min(pk) or min(rowid), and then select the corresponding rows from the table.
For hashing you could use ora_hash, but that is only for school work. If this is a serious project, you probably need to use dbms_crypto.hash.
Whether this is a correct solution depends on the possibility of collisions when hashing the BLOB values. In Oracle 11.1 - 11.2 you can use SHA-1 hashes (160 bits); perhaps this is enough to distinguish between your BLOB values. In higher Oracle versions, longer hashes (up to 512 bits in my version, 12.2) are available. Obviously, the longer the hashes, the slower the query - but also the higher the likelihood that you won't incorrectly identify different BLOB values as "duplicates" due to collisions.
Other responders asked about or mentioned a primary key (pk) column or columns in your table. If you have one, you can use it instead of the rowid in my query below - but rowid should work OK for this. (Still, pk is preferred if your table has one.)
dbms_crypto.hash takes an integer argument (1, 2, 3, etc.) for the hashing algorithm to be used. These are defined as named constants in the package. Alas, in SQL you can't reference package constants; you need to find the values beforehand. (Or, in Oracle 12.1 or higher, you can do it on the fly, by including a function in a with clause - but let's keep it simple.)
So, to cover Oracle 11.1 and higher, I'll assume we want to use the SHA-1 algorithm. To find its integer value from the package, I can do this:
begin
dbms_output.put_line(dbms_crypto.hash_sh1);
end;
/
3
PL/SQL procedure successfully completed.
If your Oracle version is higher, you can check for the value of hash_sh256, for example; on my system, it's 4. Remember this number, since we will use it below.
The query is:
select {whatever columns you need, including the BLOB}
from {your table}
where rowid in (
select min(rowid)
from {your table}
group by {the non-BLOB columns},
dbms_crypto.hash({BLOB column}, 3)
)
;
Notice the number 3 used in the hash function - that's the value of dbms_crypto.hash_sh1, which we found earlier.
I used below query to get the distinct rows including BLOB column.
select
attachsysfilename,
file_seq,
version,
lastupddttm,
lastupdoprid,
file_data,
ROW_NUMBER() OVER (PARTITION BY attachsysfilename,file_seq,version,lastupddttm,lastupdoprid ORDER BY attachsysfilename ,file_seq ,version,lastupddttm DESC,lastupdoprid) RNK
from ps_lp_ex_fileattch a
) WHERE RNK=1
This question already has answers here:
SQL IN Clause 1000 item limit
(5 answers)
how to select a list of 10,000 unique ids from dual in oracle SQL
(4 answers)
Closed 2 years ago.
When i pass value more than 1000 in In clause and try to Run Query in Oracle i found error that is "ORA-01795" that maximum number of expressions in a list is 1000 , so let me know how to solve this
A simple way is to put those values into a table and use it (the table) as a subquery, e.g.
select *
from your_table
where id in (select id from your_new_table)
There are other options, but - from my point of view - this is the simplest and easiest to maintain.
The "new table" can even be a global (or private, depending on your database version) temporary table so you'd fill it at the beginning and use throughout the session (or transaction, depending on how you created the GTT). Once you're done, its contents is "lost" and table doesn't occupy space.
The restriction only applies to single column comparisons. A strange looking workaround is to use a two-column comparison with one constant:
So instead of
select *
from some_table
where id in (1, 2, 3, .... 1001);
you can use:
select *
from some_table
where (id, -42) in (1, -42), (2, -42), ... (1001, -42)
Not sure about the performance implications with regards to index usage though (but then a IN clause with more than 1000 values isn't like to use an index to begin with)
Those 3 queries return the same result set but use 2 different technics. Is there an advantage using one over the other? The plan and the execution time are in the same cost range.
Select *
from user_tab_columns
order by data_length desc,table_name, column_name
fetch first 5 rows only
Select *
from user_tab_columns
order by data_length desc,table_name, column_name
fetch next 5 rows only
select *
from (
Select *
from user_tab_columns
order by data_length desc,table_name, column_name
)
where rownum <=5
The keywords first and next as used in the fetch clause are perfect substitutes for each other, they can be used interchangeably - this is stated clearly in the documentation. So you really only have two queries there, not three. (The first two are really identical.)
The first query is easier to write and maintain than the last query. On the other hand, it is only available in Oracle 12.1 and later versions; in Oracle 11.2 and earlier, the only option is your last query.
The fetch clause is more flexible, for example it allows you to specify with ties (to include more than 5 rows if rows with rownum 4, 5, 6 and 7 are tied on the order by criteria, for example).
I need to make a navigation panel that shows only a subset of a possible large result set. This subset is 20 records before and 20 records after the resulted record set. As I navigate the results through the navigation panel, I'll be applying a sliding window design using ROWNUM to get the next subset. My question is does Oracle's ROWNUM build the whole table before it extracts the rows you want? Or is it intelligent enough to only generate the rows I need? I googled and I couldn't find an explanation on this.
The pre-analytic-function method for doing this would be:
select col1, col2 from (
select col1, col2, rownum rn from (
select col1, col2 from the_table order by sort_column
)
where rownum <= 20
)
where rn > 10
The Oracle optimizer will recognize in this case that it only needs to get the top 20 rows to satisfy the inner query. It will likely have to look at all the rows (unless, say, the sort column is indexed in a way that lets it avoid the sort altogether) but it will not need to do a full sort of all the rows.
Your solution will not work (as Bob correctly pointed out) but you can use row_number() to do what you want:
SELECT col1,
col2
FROM (
SELECT col1,
col2,
row_number() over (order by some_column) as rn
FROM your_table
) t
WHERE rn BETWEEN 10 AND 20
Note that this solution has the added benefit that you can order the final result on a different criteria if you want to.
Edit: forgot to answer your initial question:
With the above solution, yes Oracle will have to build the full result in order to find out the correct numbering.
With 11g and above you might improve your query using the query cache.
Concerning the question's title.
See http://www.orafaq.com/wiki/ROWNUM and this in-depth explanation by Tom Kyte.
Concerning the question's goal.
This should be what you're looking for: Paging with Oracle
I don't think your design is quite going to work out as you've planned. Oracle assigns values to ROWNUM in the order that they are produced by the query - the first row produced is assigned ROWNUM=1, the second is assigned ROWNUM=2, etc. Notice that in order to have ROWNUM=21 assigned the query must first return the first twenty rows and thus if you write a query which says
SELECT *
FROM MY_TABLE
WHERE ROWNUM >= 21 AND
ROWNUM <= 40
no rows will be returned because in order for there to be rows with ROWNUM >= 21 the query must first return all the rows with ROWNUM <= 20.
I hope this helps.
It's an old question but you should try this - http://www.inf.unideb.hu/~gabora/pagination/results.html
I am trying to execute a query like
select * from tableName where rownum=1
This query is basically to fetch the column names of the table.There are more than million records in the table.When I put the above condition its taking so much time to fetch the first row.Is there any alternate to get the first row.
This question has already been answered, I will just provide an explanation as to why sometimes a filter ROWNUM=1 or ROWNUM <= 1 may result in a long response time.
When encountering a ROWNUM filter (on a single table), the optimizer will produce a FULL SCAN with COUNT STOPKEY. This means that Oracle will start to read rows until it encounters the first N rows (here N=1). A full scan reads blocks from the first extent to the high water mark. Oracle has no way to determine which blocks contain rows and which don't beforehand, all blocks will therefore be read until N rows are found. If the first blocks are empty, it could result in many reads.
Consider the following:
SQL> /* rows will take a lot of space because of the CHAR column */
SQL> create table example (id number, fill char(2000));
Table created
SQL> insert into example
2 select rownum, 'x' from all_objects where rownum <= 100000;
100000 rows inserted
SQL> commit;
Commit complete
SQL> delete from example where id <= 99000;
99000 rows deleted
SQL> set timing on
SQL> set autotrace traceonly
SQL> select * from example where rownum = 1;
Elapsed: 00:00:05.01
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=1 Bytes=2015)
1 0 COUNT (STOPKEY)
2 1 TABLE ACCESS (FULL) OF 'EXAMPLE' (TABLE) (Cost=7 Card=1588 [..])
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
33211 consistent gets
25901 physical reads
0 redo size
2237 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
As you can see the number of consistent gets is extremely high (for a single row). This situation could be encountered in some cases where for example, you insert rows with the /*+APPEND*/ hint (thus above high water mark), and you also delete the oldest rows periodically, resulting in a lot of empty space at the beginning of the segment.
Try this:
select * from tableName where rownum<=1
There are some weird ROWNUM bugs, sometimes changing the query very slightly will fix it. I've seen this happen before, but I can't reproduce it.
Here are some discussions of similar issues: http://jonathanlewis.wordpress.com/2008/03/09/cursor_sharing/ and http://forums.oracle.com/forums/thread.jspa?threadID=946740&tstart=1
Surely Oracle has meta-data tables that you can use to get column names, like the sysibm.syscolumns table in DB2?
And, after a quick web search, that appears to be the case: see ALL_TAB_COLUMNS.
I'd use those rather than go to the actual table, something like (untested):
SELECT COLUMN_NAME
FROM ALL_TAB_COLUMNS
WHERE TABLE_NAME = "MYTABLE"
ORDER BY COLUMN_NAME;
If you are hell-bent on finding out why your query is slow, you should revert to the standard method: asking your DBMS to explain the execution plan of the query for you. For Oracle, see section 9 of this document.
There's a conversation over at Ask Tom - Oracle that seems to suggest the row numbers are created after the select phase, which may mean the query is retrieving all rows anyway. The explain will probably help establish that. If it contains FULL without COUNT STOPKEY, then that may explain the performance.
Beyond that, my knowledge of Oracle specifics diminishes and you will have to analyse the explain further.
Your query is doing a full table scan and then returning the first row.
Try
SELECT * FROM table WHERE primary_key = primary_key_value;
The first row, particularly as it pertains to ROWNUM, is arbitrarily decided by Oracle. It may not be the same from query to query, unless you provide an ORDER BY clause.
So, picking a primary key value to filter by is as good a method as any to get a single row.
I think you're slightly missing the concept of ROWNUM - according to Oracle docs: "ROWNUM is a pseudo-column that returns a row's position in a result set. ROWNUM is evaluated AFTER records are selected from the database and BEFORE the execution of ORDER BY clause."
So it returns ANY row that it consideres #1 in the result set which in your case will contain 1M rows.
You may want to check out a ROWID pseudo-column: http://psoug.org/reference/pseudocols.html
I've recently had the same problem you're describing: I want one row from the very large table as a quick, dirty, simple introspection, and "where rownum=1" alone behaves very poorly. Below is a remedy which worked for me.
Select the max() of the first term of some index, and then use it to choose some small fraction of all rows with "rownum=1". Suppose my table has some index on numerical "group-id", and compare this:
select * from my_table where rownum = 1;
-- Elapsed: 00:00:23.69
with this:
select * from my_table where rownum = 1
and group_id = (select max(group_id) from my_table);
-- Elapsed: 00:00:00.01