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)
Related
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).
This question already has answers here:
how to convert csv to table in oracle
(5 answers)
Closed 4 years ago.
We’ve got a page that displays a list of records, and the user is allowed to check the desired lines, and then get a report printed of those selected records. I’m trying to define the Oracle Report to have a single parameter which would be a comma-delimited list of the IDs to be printed. However it is not working. The SQL is something like this:
Select * from CEP_TABLE where Table_ID in (:P_IDLIST)
If I define the parameter to be numeric, I get an “invalid parameter input” error when trying to give it 654,655 – it doesn’t like having the comma.
If I define the parameter to be character, it accepts the parameter but then the database gives an “invalid number” error. It appears it is substituting the bind variable with the entire parameter in quotes – e.g.
Select * from CEP_TABLE where Table_ID in (‘654,655’)
But I want it without the quotes:
Select * from CEP_TABLE where Table_ID in (654,655)
I can get the report to work if I define multiple parameters – e.g. Table_ID in (:P1,:P2,:P3,:P4) but they could have a hundred items they want to include so it seems crazy to define 100 parameters – and really… I don’t want any limit.
Has anyone tackled this problem before? – it seems like it would be pretty common. I could have the page write out the selected ids to some temporary table and then define the query to join to that table, but that also seems excessive.
There's a hero that comes to rescue, and his name is lexical parameter.
You said that your query looks like this:
select *
from CEP_TABLE
where Table_ID in (:P_IDLIST)
Report already contains parameter named p_idlist. Now create another one, manually; let's call it lex_idlist. Its datatype should be character, its length somewhat larger than p_idlist parameter's (for example, if p_idlist is character(50), make lex_idlist character(70)).
Then rewrite query as follows:
select *
from cep_table
&lex_idlist
Go to After Parameter Form trigger which should look like this:
function AfterPForm return boolean is
begin
:lex_idlist := 'where table_id in (' || :p_idlist || ')';
return (TRUE);
end;
That's all - compile the report and run it. Enter some values into p_idlist parameter (such as 654,655). The trigger will dynamically create the WHERE clause, store it into the lexical parameter which will then "act" as if it was a real WHERE clause.
Read more about lexical parameters in online Reports Help system.
This is a very common and non-trivial question.
You need to split a single input string into its component tokens. Since I don't have your table, I illustrate how it's done on the emp table in the standard scott schema; here is how you can get the rows for the list of department numbers given in a single comma-separated string, such as '10,30':
select * from scott.emp
where deptno in
(select to_number(regexp_substr(:p_deptno, '\d+', 1, level)) from dual
connect by level <= regexp_count(:p_deptno, '\d+')
)
;
In fairness, there are also methods that don't split the string, and instead play silly games with string comparisons; but those will be quite ineffective - for example they would not allow you to use an index you may have on table_id (or on deptno in my example).
New to SQL. Pardon me if this question is a basic one. Is there a way for me to do this below
SELECT COLUMN1 as CUSTOM_NAME, <wildcard for remaining columns as is> from TABLE;
I only want COLUMN1 appear once in the final result
There is no way to make that kind of dynamic SELECT list with regular SQL*.
This is a good thing. Programming gets more difficult the more dynamic it is. Even the simple * syntax, while useful in many contexts, causes problems in production code. The Oracle SQL grammar is already more complicated than most traditional programming languages, adding a little meta language to describe what the queries return could be a nightmare.
*Well, you could create something using Oracle data cartridge, or DBMS_XMLGEN, or a trick with the PIVOT clause. But each of those solutions would be incredibly complicated and certainly not as simple as just typing the columns.
This is about as close as you will get.
It is very handy for putting the important columns up front,
while being able to scroll to the others if needed. COLUMN1 will end up being there twice.
SELECT COLUMN1 as CUSTOM_NAME,
aliasName.*
FROM TABLE aliasName;
In case you have many columns it might be worth to generate a full column list automatically instead of relying on the * selector.
So a two step approach would be to generate the column list with custom first N columns and unspecified order of the other columns, then use this generated list in your actual select statement.
-- select comma separated column names from table with the first columns being in specified order
select
LISTAGG(column_name, ', ') WITHIN GROUP (
ORDER BY decode(column_name,
'FIRST_COLUMN_NAME', 1,
'SECOND_COLUMN_NAME', 2) asc) "Columns"
from user_tab_columns
where table_name = 'TABLE_NAME';
Replace TABLE_NAME, FIRST_COLUMN_NAME and SECOND_COLUMN_NAME by your actual names, adjust the list of explicit columns as needed.
Then execute the query and use the result, which should look like
FIRST_COLUMN_NAME, SECOND_COLUMN_NAME, OTHER_COLUMN_NAMES
Ofcourse this is overhead for 5-ish columns, but if you ever run into a company database with 3 digit number of columns, this can be interesting.
I am having a problem with a simple query of a view. The view itself is nasty having union_all and most of its fields evaluated by functions. The problem is that even a very simple query can get the whole view evaluated which then takes forever.
To simplify my problem I have made this two queries
select * from horrible_view where id in (1, 2, 3); -- this works super quick
select * from horrible_view where id in (select id from my_temp_table); -- this takes forever
select * from my_temp_table t left join horrible_view h on t.id=h.id -- this also takes forever
So even though my_temp_table contains the same 1, 2, 3 (3 rows with just one column) the second and third query makes the optimizer go bananas, so that the horrible view is evaluated completly and then returns just the 3 rows are returned.
Is there anything I could do?
IE in the second example make optimizer run the "select id from my_temp_table" first and then the query.
Oracle's version is 11.2
Further info:
First off I know only a little about Oracle. (So is the Explain plan from sqlDeveloper the thing you want? If so how can you print it, its huge?) Well here is the screenshot: here
I have created the temp table just in order to test. Its actually named TMP_R (and it has 10 rows)
I have to use Hibernate and retrieve data from Oracle but the problem is, that the number of parameters passed to the query is not always the same.
For the sake of simplicity let's consider the following query:
select COL_1, COL_2, ..., COL_N from TAB_1 where COL_1 in (?, ?, ... ?)
The number of parameters passed to in clause is between 1 and 500. If the number is about 1-50 it works quite fast, but for 200 it takes a few seconds to execute the query (parsing, creating explain plan, executing the query). Indexes are created and used - it was checked.
The query is created dynamicly so I use Hibernate Criteria API. For the first query (with > 100 parameters) it takes 3-5 seconds, but for the next one it works faster (even if the number of parameters varies). I would like to improve the response time for the first query. What can I do in that case assuming that Hibernate is a must?
I though about removig this dynamic query, creating a few static queries as named queries in xml file (in that case those queries will be precompiled at the beginning) For example
1) one query if the number of parameters is less then 50.
In this case if we have 30 parameters than the query would look like:
select COL_1, COL_2, ..., COL_N from TAB_1 where COL_1 in (PAR_1, PAR_2, ..., PAR_30, -1, -1 , ..., -1 ?)
2) the second one if the number is between 50 and 100 etc.
The problem is that it's not so simple using named queries and HQL (in JDBC it would be straighforward). In HQL we passed only a list and we don't specify a number of parameters in that list i.e. In fact there is only one query
'from Person where id in (:person_list)'
myQuery.setParameterList("person_list", myList)
Is there any option to solve that?
By the way, I thought that the explain plan is executed for each new query so for example:
(a) select COL_1, COL_2, ..., COL_N from TAB_1 where COL_1 in (?, ?, ..., ?) <100> - explain plan must be created
(b) select COL_1, COL_2, ..., COL_N from TAB_1 where COL_1 in (?, ?, ..., ?) <100> - explain plan won't be created because it already exists in cache
(c) select COL_1, COL_2, ..., COL_N from TAB_1 where COL_1 in (?, ?, ..., ?) <120> - explain plan should be created (there is no explain plan for a query with 120 parameters) but it takes less time in comparison with (a), almost the same as (b) so probably Oracle can create this plan faster if a similar query was executed before
What is the reason for that?
There are a couple of things here. First of all, you cannot bind an IN list, at least I am pretty sure you cannot. I suspect Hibernate is using some sort of trick you put your array contents into a static inlist Oracle can use.
Secondly if this query is executed with lots of different parameters, you must you bind variables or the performance of the entire database will suffer.
That said, there is a way to bind an IN list using a 'trick' which Tom Kyte describes on his blog -
http://tkyte.blogspot.com/2006/01/how-can-i.html
The code in there looks like:
ops$tkyte#ORA10GR2> with bound_inlist
2 as
3 (
4 select
5 substr(txt,
6 instr (txt, ',', 1, level ) + 1,
7 instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 )
8 as token
9 from (select ','||:txt||',' txt from dual)
10 connect by level <= length(:txt)-length(replace(:txt,',',''))+1
11 )
12 select *
13 from all_users
14 where user_id in (select * from bound_inlist);
USERNAME USER_ID CREATED
------------------------------ ---------- ---------
SYSTEM 5 30-JUN-05
OPS$TKYTE 104 20-JAN-06
The part:
12 select *
13 from all_users
14 where user_id in (select * from bound_inlist);
Is basically where your query goes. The bit above is the trick which splits the comma separated string into a list of values. Instead of binding a list into the :txt placeholder, you would need to convert the list to a string and just bind that.
Are you sure the difference in query times isn't due to caching or load variations on the machine? Parsing the query will take a little time, but several seconds is a long time.
I've worked with IN(...) queries that had up to a 1000 of ids in that list; I can guarantee you that it does not take several seconds to parse / prepare / cache a statement.
Hibernate does indeed auto-expand the parameter list you specify using the actual number of elements in the list you pass, so if you really wanted to keep it "fixed" at a certain level all you need to do is to append enough -1s to the end. However, this is most certainly not the problem especially since we're talking about speeding up the first query run - no statements have been prepared / cached yet anyway.
Did you look at the execution plans for your queries? Both via explain plan and autotrace enabled? Do they differ when you have 30 elements and 120 elements in your list? Does your actual query really look like "select ... from table where id in (...)" you've posted or is it more complex? I'm willing to bet that somewhere between 30 and 120 elements Oracle decides (perhaps mistakenly) that it'll be faster not to use an index, which is why you're seeing the time increase.