Array in Where Clause
Hi,
I am having a function with an IN paramter as an array.
How do i use all the values in this array in the Where clause?
Function ( tArrayOfNos IN tArrType )
open Tstcursor FOR
select ...
from ...
where tNo in <all the nos in the array tArrayOfNos >
thanks for your help..
>
If i define the type inside my package and try to use the Member Of in a function, it doesn't work..
>
In the examples above you will need to have a type declared in the database, however you can create a pipelined function... something like this,
SQL> CREATE OR REPLACE Package My_Types Is
2
3 Type enames_tab Is Table Of Varchar2(50);
4
5 End My_Types;
6 /
Package created
SQL> CREATE OR REPLACE Function lookup_ename Return my_types.enames_tab
2 Pipelined Is
3 v_row my_types.enames_tab;
4 cur Sys_Refcursor;
5 v_ename Varchar2(50);
6 Begin
7 v_row := my_types.enames_tab();
8 Open cur For
9 SELECT ename
10 FROM emp
11 WHERE ename IN ('SMITH', 'JAMES', 'WARD');
12 Loop
13 Fetch cur
14 INTO v_ename;
15 Exit When cur%Notfound;
16 v_row.Extend;
17 v_row(v_row.Count) := v_ename;
18 Pipe Row(v_row(v_row.Count));
19 End Loop;
20 Return;
21 End;
22 /
Function created
SQL> Set Serveroutput on;
SQL> Declare
2 v_tab my_types.enames_tab;
3 Begin
4 SELECT ename Bulk Collect
5 INTO v_tab
6 FROM emp
7 WHERE ename Member Of lookup_ename;
8
9 For i IN v_tab.First .. v_tab.Last Loop
10 dbms_output.put_line(v_tab(I));
11 End Loop;
12 End;
13 /
SMITH
WARD
JAMES
PL/SQL procedure successfully completed
Similar Messages
-
How to change recordset bahaviour to accept dynamic column names in the where clause
Hi
im using php-mysql and i make a recordset and i want to make the column names in the where clause to be dynamic like
"select id,name from mytable where $tablename-$myvar";
but when i do this my i break the recordset and it disappear
and when i use variables from advanced recordset it only dynamic for the value of the column not for the column name
and when i write the column name to dynamic as above by hand it truns a red exclamation mark on the server behaviour panel
so i think the only way is to change the recordset behaviour is it? if so How to make it accept dynamic column names?
thanks in advance.As bregent has already explained to you, customizing the recordset code will result in Dreamweaver no longer recognizing the server behavior. This isn't a problem, but it does mean that you need to lay out your dynamic text with the Bindings panel before making any changes. Once you have changed the recordset code, the Bindings panel will no longer recognize the recordset fields.
Using a variable to choose a column name is quite simple, but you need to take some security measures to ensure that the value passed through the query string isn't attempting SQL injection. An effective way of doing this is to create an array of acceptable column names, and check that the value matches.
// create array of acceptable values
$valid = array('column_name1', 'column_name2', 'column_name3');
// if the query string contains an acceptable column name, use it
if (isset($_GET['colname']) && in_array($_GET['colname'], $valid)) {
$col = $GET['colname'];
} else {
// set a default value if the submitted one was invalid
$col = 'column_name1'
You can then use $col directly in the SQL query. -
Using a WHERE clause in APEX Tree
Hi All -
I have an hierarchical SQL query that I'm displaying as an APEX tree.
My sample app is here:
https://apex.oracle.com/pls/apex/f?p=32581:29
login: guest
pw: app_1000
workspace: leppard
I am trying to add a WHERE clause so that only nodes with the lowest level children are displayed, i.e. something like 'WHERE connect_by_isleaf = 0 OR level = 5'
The tree query with the where clause works fine in the SQL commands window, but when I add the WHERE clause to my apex tree the page no longer displays anything. Is this an issue with APEX or is there some other way to filter my results?
Thanks in advance for any suggestions,
johnConnect by occurs first, the where clause then is applied to those results, effectively cutting away in the hierarchical structure. Since apex has to build a hierarchical structure from the query it relies on the level pseudocolumn, which is butchered by applying the where clause. It's a miracle you aren't even receiving errors because I'd almost expect an incorrect json array to have been built. With no top level to start from and only level 5 or leaf nodes there is no structure to present: both apex can not put out a correct representation and not jstree either. In your query you will see your "root nodes" but it is not representable.
I'm not sure why you want to present this in a tree? Both connect_by_is_leaf and level = 5 will simply give you a list of nodes without any hierarchical structure.
The better thing to do is to use a subquery to first limit your dataset and then use that to base the tree query on, that way you don't break any of those vital columns.
Eg if you only want leaf nodes and their immediate parent you could go for something like this (quick mockup on some testdata):
with dataset as (
select node_id, parent_id
from treedata
where connect_by_isleaf = 0
connect by prior node_id = parent_id
start with parent_id = 0
dataset2 as (
select node_id, parent_id
from dataset
union all
select node_id, null parent_id
from treedata
where node_id in (select parent_id from dataset)
select level, node_id
from dataset2
connect by prior node_id = parent_id
start with parent_id is null -
Using multiple values in a where clause, for values only known at runtime
Dear all
I am creating a PL/SQL program which returns multiple rows of data but only where it meets a set id values that a user has previously chosen. The id values are stored in an associative array and are chosen by a user in the preceding procedure at run time.
I know all the table and column names in advance. The only things I don't know are the exact number of ids selected from the id column and what their values will be. This will only be known at runtime. When the procedure is run by the user it prints multiple rows of data to a web browser.
I have been reading the following posting, which I understand to a large extent, Query for multiple value search But I cannot seem to figure out how I would apply it to my work as I am dealing with multiple rows and a cursor.
The code as I have currently written it is wrong because I get an error not found message in my web browser. I think the var_user_chosen_map_list_ids in the for cursor loop could be the problem. I am using the variable_user_chosen_map_list_ids to store all the id values from my associatative array as a string. Which I modified from the code that vidyadhars posted in the other thread.
Should I be creating a OPEN FOR ref cursor and if so where would I put my associative array into it? At the moment I take the value, turning it into a string and IN part in the WHERE clause holds the string, allowing the WHERE clause to read all the values from it. I would expect the where clause to read everything in the string as 1 complete string of VARCHAR2 data but this would not be the case if this part of the code at least was correct. The code is as follows:
--Global variable section contains:
var_user_chosen_map_list_ids VARCHAR2(32767);
PROCEDURE PROCMAPSEARCH (par_user_chosen_map_list_ids PKG_ARR_MAPS.ARR_MAP_LIST)
IS
CURSOR cur_map_search (par_user_chosen_map_list_ids IN NUMBER)
IS
SELECT MI.map_date
MT.map_title,
FROM map_info MI,
map_title MT,
WHERE MI.map_title_id = MT.map_title_id
AND MI.map_publication_id IN
(var_user_chosen_map_list_ids);
var_map_list_to_compare VARCHAR2(32767) := '';
var_exe_imm_map VARCHAR2(32767);
BEGIN
FOR rec_user_chosen_map_list_ids IN 1 .. par_user_chosen_map_list_ids.count
LOOP
var_user_chosen_map_list_ids := var_user_chosen_map_list_ids ||
'''' ||
par_user_chosen_map_list_ids(rec_user_chosen_map_list_ids) ||
END LOOP;
var_user_chosen_map_list_ids := substr(var_user_chosen_map_list_ids,
1,
length(var_user_chosen_map_list_ids)-1);
var_exe_imm_map := 'FOR rec_search_entered_details IN cur_map_search
LOOP
htp.print('Map date: ' || cur_map_search.map_date || ' Map title: ' || cur_map_search.map_title)
END LOOP;';
END PROCMAPSEARCH;EXECUTE IMMEDIATE var_exe_imm_map;
I would be grateful of any comments or advice.
Kind regards
TimI would like to thank everyone for their kind help.
I have now successfully converted my code for use with dynamic SQL. Part of my problem was getting the concept confused a little, especially as I could get everything work in a static cursor, including variables, as long as they did not contain multiple values. I have learnt that dynamic sql runs the complete select statement at runtime. However even with this I was getting concepts confused. For example I was including variables and the terminator; inside my select string, where as these should be outside it. For example the following is wrong:
TABLE (sys.dbms_debug_vc2coll(par_user_chosen_map_list_ids))....
AND MI.map_publication_id = column_value;';Where as the following is correct:
TABLE (sys.dbms_debug_vc2coll('||par_user_chosen_map_list_ids||'))....
AND MI.map_publication_id = column_value';PL/SQL is inserting the values and then running the select statement, as opposed to running the select statement with the variables and then accessing the values stored in those variables. Once I resolved that it worked. My revised code is as follows:
--Global variable section contains:
var_user_chosen_map_list_ids VARCHAR2(32767);
var_details VARCHAR(32767);
PROCEDURE PROCMAPSEARCH (par_user_chosen_map_list_ids PKG_ARR_MAPS.ARR_MAP_LIST)
IS
BEGIN
FOR rec_user_chosen_map_list_ids IN 1 .. par_user_chosen_map_list_ids.count
LOOP
var_user_chosen_map_list_ids := var_user_chosen_map_list_ids ||
'''' ||
par_user_chosen_map_list_ids(rec_user_chosen_map_list_ids) ||
END LOOP;
var_user_chosen_map_list_ids := substr(var_user_chosen_map_list_ids,
1,
length(var_user_chosen_map_list_ids)-1);
var_details := FUNCMAPDATAFIND (var_user_chosen_map_list_ids);
htp.print(var_details);
END PROCMAPSEARCH;
FUNCTION FUNCMAPDETAILS (par_user_chosen_map_list_ids IN VARCHAR2(32767)
RETURN VARCHAR2
AS
TYPE cur_type_map_search IS REF CURSOR;
cur_map_search cur_type_map_search;
var_map_date NUMBER(4);
var_map_title VARCHAR2(32767);
begin:
OPEN cur_map_search FOR
'SELECT MI.map_date,
MT.map_title
FROM map_info MI,
map_title MT,
TABLE (sys.dbms_debug_vc2coll(' || par_user_chosen_map_list_ids || '))
WHERE MI.map_title_id = MT.map_title_id
AND MI.map_publication_id = column_value';
LOOP
FETCH cur_map_compare INTO
var_map_date,
var_map_title;
var_details := var_details || 'Map date: '||
var_map_date ||
'Map title: ' ||
var_map_title;
EXIT WHEN cur_map_compare%NOTFOUND;
END LOOP;
RETURN var_details;
END FUNCMAPDETAILS;Kind regards
Tim -
Using collections in WHERE clause
Hi friends,
Please help me to use an associate array in SQL query (WHERE clause). The requirement is similar to the following example:
===============================================
declare
type rec_emp is record(emp_id integer, emp_name varchar2(100));
type ty_emp is table of rec_emp index by pls_integer;
tb_emp ty_emp;
type ty_emp_history is table of emp_history%rowtype index by pls_integer;
tb_emp_history ty_emp_history;
begin
select emp_id, emp_name
bulk collect into tb_emp
from emp
where dept_id = 10;
--Now I want to fetch records from emp_history based on the values in tb_emp. So I want a query something like the following.
--(I know that join can be used to achive this. But it is just an example. I need to achive this in collections.)
select *
bulk collect into tb_emp_history
from emp_history
where emp_id = tb_emp.emp_id
and emp_name = tb_emp.emp_name;
end;
===============================================
Thanks in advance.
Edited by: Iniyavan on Oct 26, 2012 11:50 AM>
Please help me to use an associate array in SQL query (WHERE clause).
select *
bulk collect into some_array
>
there is no variable 'some_array' in what you posted.
If you want help with your code you have to post the code you are really using, not some hacked-up version of it that has errors.
Here is sample code that shows how to treat a collection as a table using the TABLE operator
-- type to match emp record
create or replace type emp_scalar_type as object
(EMPNO NUMBER(4) ,
ENAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIREDATE DATE,
SAL NUMBER(7, 2),
COMM NUMBER(7, 2),
DEPTNO NUMBER(2)
-- table of emp records
create or replace type emp_table_type as table of emp_scalar_type
declare
tb emp_table_type;
deptnoList sys.OdciNumberList;
BEGIN
select emp_scalar_type(empno, ename, job, mgr, hiredate, sal, comm, deptno)
bulk collect into tb from emp;
SELECT deptno bulk collect
INTO deptnoList
FROM dept where deptno not in (select deptno from table(tb));
for i in 1..deptnoList.count loop
dbms_output.put_Line(deptnoList(i));
end loop;
END;Note that tb is a collection and is useds in the subquery 'select deptno from table(tb)'. -
How to modify the where clause in this to include other things
How do I modify the WHERE clause in this code:
$expected = array(first_name, last_name, level, language, 'city', 'state', 'zip', );
$query_search = 'SELECT * FROM french;
$where = false;
foreach ($expected as $var) {
if (isset($_GET[$var]) && !empty($_GET[$var])) {
if ($where) {
$query_search .= ' AND ';
} else {
$query_search .= ' WHERE ';
$where = true;
$query_search .= $var . ' = '. GetSQLValueString($_GET[$var], 'text');
to include things like searching multiple columns and IF NULL:
SELECT * from MyTable where (MyCol1 = %s or MyCol1 Is Null) AND (MyCol2 = %s or MyCol2 Is Null)
Where on earth does it go?
Thanks
BrianMy goal is to have a search form and results combination that:
1) allows the user to ignore any of the page’s existing search fields that
they don’t need, (to search with empty form fields);
2) to use whichever search form fields they choose to use even if the
Registrant for whom they are searching did not insert that information when
they registered, (they are filled in the search form but empty in the
database table);
3) and to permit some of the seach fields to search multiple columns, for
example the search form field ‘sonsName’ would look for that information in
three different database table colums, (sonsName1, sonsName2 etc.).
You’ve given me code that permits 1) above to work beautifully. You’ve also
sent along code that should let me accomplish the other two, and though I’ve
been able to recreate below what I want the multiple search column to do, I
can get neither the multiple column nor the IS NULL sections to work in the
code you sent most recently.
How do I take something like this:
$colname_rsSearch = "-1";
if (isset($_POST['first_name_now'])) {
$colname_rsSearch = $_POST['first_name_now'];
$colname2_rsSearch = "-1";
if (isset($_POST['last_name_now'])) {
$colname2_rsSearch = $_POST['last_name_now'];
$colname3_rsSearch = "-1";
if (isset($_POST['sonsName'])) {
$colname3_rsSearch = $_POST['sonsName'];
mysql_select_db($database_connStr_Milo_db, $connStr_Milo_db);
$query_rsSearch = sprintf("SELECT milo.first_name_now, milo.last_name_now,
milo.ws_number, milo.ws_number_3, milo.ws_number_4 FROM milo WHERE
milo.first_name_now = %s AND milo.last_name_now = %s AND (milo.sonsName1 =
%s) || (milo.sonsName2 = %s) || (milo.sonsName3 = %s)",
GetSQLValueString($colname_rsSearch,
"text"),GetSQLValueString($colname2_rsSearch,
"text"),GetSQLValueString($colname3_rsSearch,
"text"),GetSQLValueString($colname3_rsSearch,
"text"),GetSQLValueString($colname3_rsSearch, "text"));
$rsSearch = mysql_query($query_rsSearch, $connStr_Milo_db) or
die(mysql_error());
$row_rsSearch = mysql_fetch_assoc($rsSearch);
$totalRows_rsSearch = mysql_num_rows($rsSearch);
?> (I’ve excluded the IS NULL part from my example, but need it in the final
version)
…and make it work using your code below (which permits someone to search
with empty form fields, but does not yet enlighten me on what to group (with
parenthesis) to make the code execute the multiple column search and the IS
NULL parts of the search.
mysql_select_db($database_connStr_Milo_db, $connStr_Milo_db);
$expected = array('first_name_now', 'last_name_now', sonsName'
$query_search = 'SELECT milo.first_name_now, milo.last_name_now,
milo.ws_number, milo.ws_number_3, milo.ws_number_4 FROM milo';
$where = false;
foreach ($expected as $var) {
if (isset($_POST[$var]) && !empty($_POST[$var])) {
if ($where) {
$query_search .= ' AND ';
} else {
$query_search .= ' WHERE ';
$where = true;
$query_search .= '(' . $var . ' = '. GetSQLValueString($_POST[$var],
'text') .
' OR ' . $var . ' IS NULL)';
$search = mysql_query($query_search, $connStr_Milo_db) or
die(mysql_error());
$row_search = mysql_fetch_assoc($search);
$totalRows_search = mysql_num_rows($search);
As always, thank you. -
Hi,
Is there a nice way to specify the list eg.
where itemNo IN(:1/?),
where i can just set the where clause parameter with a array?If TABLE_OF_VARCHAR is a table type declared like this:
CREATE TYPE TABLE_OF_VARCHAR AS TABLE OF VARCHAR2(2000);
Then you can do this:
select ...
from ...
where column_value in (select *
from TABLE(CAST(? as TABLE_OF_VARCHAR)))
this allows you to set an array-valued bind variable and cast its values into a table to select in the IN clause.
This lets you have a variable number of args in the IN clause in a way that doesn't change the text of the SQL statement each time.
I've posted a working sample project at:
http://www.geocities.com/smuench/ArrayOfStringDomain.zip -
Parsing an input parameter for the where clause or record select value
In my limited CR experience, I've always used a command database connection so that I can write my own SQL. However, now I have to parse a pipe delimited parameter to get my value for the where clause, so I'm selecting several tables and joining them through the Database Expert Links tab. All works fine, but after doing that and then parsing the parameter with the below formula in the Select Expert, I notice that there is no where clause in the SQL query, and although the report eventually displays the proper values, it runs through thousands of records first. Here is my Select Expert - Record formula:
StringVar array Parm1;
Parm1 := Split({?DATA_AREA}, "|");
{SO_ORDERS.CASE_ID} = Parm1[2]
If I change "Parm1[2]" on the last line to a valid Case ID, then there is a where clause in the SQL and the report generates immediately.
It seems like the record select formula is applied AFTER all of the records (without a where clause) are searched when I use the parsed parameter value, but when I hard code a valid value, it places that into the where clause BEFORE the sql is executed. Is there a way to get the parameter parsed first and then use that parsed value in the SQL where clause?
Thanks.
BillYes crystal will run the query first to get 100% data and then applies record selection condition. To increase the performance you need to pass the where condition at the command level instead of report level. So you need to create a report using add command like this
select * from tablename where field={?Parameter}
{?Parameter} is a command level parameter.
Now insert this report as a subreport in another report which has no connection but has a parameter
{?DATA_AREA} and create a formula like this in the main report
Split({?DATA_AREA}, "|")[2]
Now right click on the subreport and go to change subreport links and add this formula from main report and link this to sub report parameter {?Parameter} without linking any database field from the subreport.
Now your subreport runs with the where clause to get the data.
Regards,
Raghavendra -
Dynamic where clause - hard-parse
Hi there,
I landed in the middle of a situation that I'm not seeing any solution possible, so I’m turning to you for help.
We have a batch script that occurs once a day that handles a lot of information (we're talking about thousands of data).
In many situations we have to run select's with the where clause dynamically build.
That is, we have a table with something like: ID - COLUMN_NAME - OPPERATOR - COLUMN_VALUE - DEPENDING_VALUE
Our database is unique for a large number of clients (we have about 90% of my country City Hall's and then some more...), and DEPENDING_VALUE depends on each client.
So, for each client, we build the where clause based on that table and then we get the data from another table with something like SELECT ABC FROM XPTO WHERE || WHERE_CLAUSE_BUILD using dynamic sql.
So far so good, except we can have many different combinations of the where clause causing the select to be hard-parse for each client and we are trying to think of a better way to do this. Unfortunately we haven’t found one yet and I’m not seeing any light in the end of the tunnel…
This is kind of difficult to explain, so I hope I was clear enough.
Any help would be greatly appreciated.
Thank youHi, thank you for your answer.
We are already using the USING clause and binding.
The (we think kind of stupid) idea we had was:
We created an array of 100 positions.
Then we made a function that get’s the where clause and populates the array making something like:
‘where a = :param1 and b = :param2 and c= :param3’ and so on.
For the remaining positions, we added ‘and 1 = :paramMax+1 and … and 1 = :paramMax+N and …’ and put :paramMax+1.value = 1 and :paramMax+N = 1.
Then, when using the select with the where clause we opened a cursor using :param1.value, :param2.value, :param3.value, … :param100.value
But this still is hard-parsing because I can have:
Select x from y where a = :param1 and b = :param2 and 1 = :param3 …
And for another client
Select x from y where a = :param1 and 1 = :param2 and 1 = :param3 …
The statements are different, that’s why I’m not seeing any solution.
Thanks -
Filter Records in WHERE clause iReports using values passed from a prgram
I have searched for iReports manual and what i can see are docs on sale. I have managed to create jrxml file, execute it in jsp and actually view the report.
Now i have a big list of customers from various branches and have various categories. I would like to know how to pass the parameters so that i retrieve a small list of items. e.g. WHERE cu.branch=200 AND cu.category=10. That is i would like to pass 20 and 10 to the jrxml query stored.
In iReports i saw parameters, variables and fields but it seems like these are displayable fields.
How will i achieve this. Am seeking for assistance.
null>
Please help me to use an associate array in SQL query (WHERE clause).
select *
bulk collect into some_array
>
there is no variable 'some_array' in what you posted.
If you want help with your code you have to post the code you are really using, not some hacked-up version of it that has errors.
Here is sample code that shows how to treat a collection as a table using the TABLE operator
-- type to match emp record
create or replace type emp_scalar_type as object
(EMPNO NUMBER(4) ,
ENAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIREDATE DATE,
SAL NUMBER(7, 2),
COMM NUMBER(7, 2),
DEPTNO NUMBER(2)
-- table of emp records
create or replace type emp_table_type as table of emp_scalar_type
declare
tb emp_table_type;
deptnoList sys.OdciNumberList;
BEGIN
select emp_scalar_type(empno, ename, job, mgr, hiredate, sal, comm, deptno)
bulk collect into tb from emp;
SELECT deptno bulk collect
INTO deptnoList
FROM dept where deptno not in (select deptno from table(tb));
for i in 1..deptnoList.count loop
dbms_output.put_Line(deptnoList(i));
end loop;
END;Note that tb is a collection and is useds in the subquery 'select deptno from table(tb)'. -
Derive found flag in SQL with where clause using TABLE(CAST function
Dear All,
Stored procedure listEmployees
==========================
CREATE OR REPLACE TYPE STRING_ARRAY AS VARRAY(8000) OF VARCHAR2(15);
empIdList STRING_ARRAY
countriesList STRING_ARRAY
SELECT EMP_ID, EMP_COUNTRY, EMP_NAME, FOUND_FLAG_
FROM EMPLOYEE WHERE
EMP_ID IN
(SELECT * FROM TABLE(CAST(empIdList AS STRING_ARRAY))
AND EMP_COUNTRY IN
(SELECT * FROM TABLE(CAST(countriesList AS STRING_ARRAY))
=================
I have a stored procedure which lists the employees using above simple query.
Here I am using table CAST function to find the list of employees in one go
instead of looping through each and every employee
Everything fine until requirements forced me to get the FOUND_FLAG as well.
Now I wanted derive the FOUND_FLAG by using rownum, rowid, decode functions
but I was not successful
Can you please suggest if there is any intelligent way to say weather the
row is found for given parameters in the where clause?
If not I may have to loop through each set of empIdList, countriesList
and find the values individually just to set a flag. In this approach I can’t use
the TABLE CAST function which is efficient I suppose.
Note that query STRING_ARRAY is an VARRAY. It is very big in size and this procedure
suppose to handle large sets of data.
Thanks In advance
Regards
Charan
Edited by: kmcharan on 03-Dec-2009 09:55
Edited by: kmcharan on 03-Dec-2009 09:55If your query returns results, you have found them... so your "FOUND" flag might be a constant,...
-
Index usage in depending on where clause changes.
Hello Friends,
I need your help for one issue.
I have one query , which is using two table Say T1 and T2, where C1 is common column using which both are joined.
C1 is primary key in T1, but no index available in T2 for C1. T1C2 is the column which we want to select.
(Note that Either of table can be a Master table)
Now see the query:
Select T1C2
From T1, T2
where T2.C1 = T1.C1
Here where clause may have other conditions and From clause may have others tables as per requirements.
I want to know that, if, I change the query like following to let my query use the available index of T1.C1.
Select T1C2
from T1, T2
where T1.C1 = T2.C1
Then, Will the query use the available index of T1. and Will i get better performance. Even a little improvement in performance may help me a lot as this kind of query is being used within a where loop (so it is going to be executed multiple times).
Please advise on this..
Regards,
Dipali..Hi,
18:43:17 rel15_real_p>create table t1(c1 number primary key, c2 number);
Table created.
18:43:26 rel15_real_p>create table t2(c1 number, c2 number);
18:45:08 rel15_real_p>
18:45:09 rel15_real_p>begin
18:45:09 2 for i in 1..100
18:45:09 3 loop
18:45:09 4 insert into t1(c1,c2) values (i,i+100);
18:45:09 5 end loop;
18:45:09 6 commit;
18:45:09 7 end;
18:45:09 8 /
PL/SQL procedure successfully completed.
18:45:09 rel15_real_p>
18:45:09 rel15_real_p>
18:45:09 rel15_real_p>begin
18:45:09 2 for i in 1..100
18:45:09 3 loop
18:45:09 4 insert into t2(c1,c2) values (i,i+200);
18:45:09 5 end loop;
18:45:09 6 commit;
18:45:09 7 end;
18:45:09 8 /
18:45:23 rel15_real_p>select count(*) from t1;
COUNT(*)
100
18:45:30 rel15_real_p>select count(*) from t2;
COUNT(*)
100
18:45:49 rel15_real_p>select index_name,index_type from user_indexes where table
_name='T1';
INDEX_NAME INDEX_TYPE
SYS_C0013059 NORMAL
18:48:21 rel15_real_p>set autotrace on
18:52:25 rel15_real_p>Select T1.C2
18:52:29 2 From T1, T2
18:52:29 3 where T2.C1 = T1.C1
18:52:29 4 /
C2
101
102
103
104
105
C2
200
100 rows selected.
Execution Plan
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=100 Bytes=
900)
1 0 HASH JOIN (Cost=7 Card=100 Bytes=3900)
2 1 TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=3 Card=100 By
es=2600)
3 1 TABLE ACCESS (FULL) OF 'T2' (TABLE) (Cost=3 Card=100 By
es=1300)
Statistics
0 recursive calls
0 db block gets
21 consistent gets
0 physical reads
0 redo size
1393 bytes sent via SQL*Net to client
562 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
100 rows processed
18:52:31 rel15_real_p>analyze table t1 compute statistics;
Table analyzed.
18:55:35 rel15_real_p>analyze table t2 compute statistics;
18:55:38 rel15_real_p>set autotrace on
18:55:42 rel15_real_p>Select T1.C2
18:55:43 2 From T1, T2
18:55:45 3 where T2.C1 = T1.C1
18:55:46 4 /
C2
101
102
103
104
105
C2
200
100 rows selected.
Execution Plan
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=6 Card=100 Bytes=7
00)
1 0 MERGE JOIN (Cost=6 Card=100 Bytes=700)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=2 Ca
rd=100 Bytes=500)
3 2 INDEX (FULL SCAN) OF 'SYS_C0013059' (INDEX (UNIQUE)) (
Cost=1 Card=100)
4 1 SORT (JOIN) (Cost=4 Card=100 Bytes=200)
5 4 TABLE ACCESS (FULL) OF 'T2' (TABLE) (Cost=3 Card=100 B
ytes=200)
Statistics
1 recursive calls
0 db block gets
23 consistent gets
0 physical reads
0 redo size
1393 bytes sent via SQL*Net to client
562 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
100 rows processed
18:56:56 rel15_real_p>Select T1.C2
18:56:56 2 From T1, T2
18:56:56 3 where T1.C1 = T2.C1
18:56:58 4 /
C2
101
102
103
104
105
C2
200
100 rows selected.
Execution Plan
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=6 Card=100 Bytes=7
00)
1 0 MERGE JOIN (Cost=6 Card=100 Bytes=700)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=2 Ca
rd=100 Bytes=500)
3 2 INDEX (FULL SCAN) OF 'SYS_C0013059' (INDEX (UNIQUE)) (
Cost=1 Card=100)
4 1 SORT (JOIN) (Cost=4 Card=100 Bytes=200)
5 4 TABLE ACCESS (FULL) OF 'T2' (TABLE) (Cost=3 Card=100 B
ytes=200)
Statistics
1 recursive calls
0 db block gets
23 consistent gets
0 physical reads
0 redo size
1393 bytes sent via SQL*Net to client
562 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
100 rows processed- Pavan Kumar N -
Urgent: Performance problem with where clause using IN and an OR condition
Select statement is:
select fl.feed_line_id
from ap_expense_feed_lines_all fl
where ((:1 is not null and
fl.feed_line_id in (select distinct r2.object_id
from xxdl_pcard_wf_routing_lists r2,
per_people_f hr2
where upper(hr2.full_name) like upper(:1||'%')
and hr2.person_id = r2.person_id
and r2.fyi_list is null
and r2.sequence_number <> 0))
or
(:1 is null))
If I modify the statement to remove the "or (:1 is null))" part at the bottom of the where clause, it returns in .16 seconds. If I modify the statement to only contain the "(:1 is null))" part of the where clause, it returns in .02 seconds. With the whole statement above, it returns in 477 seconds. Anyone have any suggestions?
Explain plan for the whole statement is:
(1) SELECT STATEMENT CHOOSE
Est. Rows: 10,960 Cost: 212
FILTER
(2) TABLE ACCESS FULL AP.AP_EXPENSE_FEED_LINES_ALL [Analyzed]
(2) Blocks: 8,610 Est. Rows: 10,960 of 209,260 Cost: 212
Tablespace: APD
(6) TABLE ACCESS BY INDEX ROWID HR.PER_ALL_PEOPLE_F [Analyzed]
(6) Blocks: 4,580 Est. Rows: 1 of 85,500 Cost: 2
Tablespace: HRD
(5) NESTED LOOPS
Est. Rows: 1 Cost: 4
(3) TABLE ACCESS FULL XXDL.XXDL_PCARD_WF_ROUTING_LISTS [Analyzed]
(3) Blocks: 19 Est. Rows: 1 of 1,303 Cost: 2
Tablespace: XXDLD
(4) UNIQUE INDEX RANGE SCAN HR.PER_PEOPLE_F_PK [Analyzed]
Est. Rows: 1 Cost: 1
Thanks in advance,
PeterThanks for the reply, but I have already checked what you are suggesting and I am pretty sure those are not causing the problem. The hr2.full_name column has an upper index and the (4) line of the explain plan shows that index being used. In addition, that part of the query executes on its own quickly.
Because the sql is not displayed in an indented format on this page it is a little hard to understand the structure so I am going to restate what is happening.
My sql is:
select a_column
from a_table
where ((:1 is not null) and a_column in (sub-select statement)
or
(:1 is null))
The :1 bind variable is set to a varchar2 entered on the screen of an application.
If I execute either part of the sql without the OR condition, performance is good.
If the :1 bind variable is null with the whole sql statement (so all rows or a_table are returned), performance is still good.
If the :1 bind variable is a not-null value with the whole sql statement, performance stinks.
As an example:
where (('wa' is not null) and a_column in (sub-select statement)) -- fast
where (('wa' is null)) -- fast
where (('' is not null) and a_column in (sub-select statement) -- fast
or
('' is null))
where (('wa' is not null) and a_column in (sub-select statement) -- slow
or
('wa' is null)) -
Cardinality estimator 2014 is off with OR in where clause
Here is my test setup on SQL Server 2014.
-- Create big table
CREATE TABLE [dbo].[Store](
Id int IDENTITY(1,1) NOT NULL,
City int NOT NULL,
Size int NOT NULL,
Name varchar(max) NULL,
CONSTRAINT [PK_Store] PRIMARY KEY CLUSTERED ([Id] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_Store] ON [dbo].[Store] (City ASC, Size ASC)
GO
-- Fill with 100k rows
INSERT Store
SELECT i % 101, i % 11, 'Store ' + CAST(i AS VARCHAR)
FROM
(SELECT TOP 100000 ROW_NUMBER() OVER (ORDER BY s1.[object_id]) AS i
FROM sys.all_objects s1, sys.all_objects s2) numbers
GO
-- Create small table
CREATE TABLE #StoreRequest (City int NOT NULL, Size int NOT NULL)
GO
INSERT #StoreRequest values (55, 1)
INSERT #StoreRequest values (66, 2)
Now I execute the following query (I force the index to show statistics estimates)
SELECT s.City
FROM #StoreRequest AS r
INNER JOIN Store AS s WITH(INDEX(IX_Store), FORCESEEK)
ON s.City = r.City AND s.Size = r.Size
WHERE s.Size <> 1 OR r.City <> 55
Here are the estimates that I get (I'm not allowed to upload pictures):
Index Seek IX_Store
Actual Number of Rows: 90
Estimated Number of Rows: 50000
Fixing WHERE clause to use one table not two makes the estimate perfect:
SELECT s.City
FROM #StoreRequest AS r
INNER JOIN Store AS s WITH(INDEX(IX_Store), FORCESEEK)
ON s.City = r.City AND s.Size = r.Size
WHERE s.Size <> 1 OR s.City <> 55
Index Seek IX_Store
Actual Number of Rows: 90
Estimated Number of Rows: 89.74
Switching to 2012 compatibility mode gives estimate of 1 in both cases:
Index Seek IX_Store
Actual Number of Rows: 90
Estimated Number of Rows: 1
Could anyone explain the first result? I'm a bit worried about it. The fix in this case is trivial, but this problem gave us quite some headache in more complex real life queries with multiple joins.
Thank you!But not full statistics on a field basis, just sometimes some default stats like total row count that some plans will build. Even your StoreRequest table only has one two-field index that will have a full histogram.
But I've seen SQL Server make massively bad plans on two-field indexes.
I've seen SQL Server go wrong one-column indexes, so that is not a very relevant point.
Temp tables or not, the estimate here is clearly incorrect. SQL Server knows the density of Size and City. It knows the cardinality of the temp table. The density information gives how many rows the the join will produce. The WHERE clause will then remove
a certain number of rows. With no statistics for the temp table, it does not now how many, but it will apply some standard guess.
50000 is a completely bogus number, because the join cannot produce that many rows, and SQL Server is able to compute the join with out the WHERE clause decently. (Well, it estimates 90, when the number is 180.) No, this is obviously a case of the cardinality
estimator giving up completely.
It is worth noting that both these WHERE clauses gives reasonable estimates:
WHERE r.Size <> 11 OR r.City <> 550
WHERE s.Size <> 11 OR s.City <> 550
Whereas these two gives the spooky 50000:
WHERE s.Size <> 11 OR r.City <> 550
WHERE r.Size <> 11 OR s.City <> 550
Erland Sommarskog, SQL Server MVP, [email protected] -
Trouble with OR in where clause
Hello,
I'm having trouble with execution speed. The problem seems to be with using OR in my where clause.
Here's the meat of the function where i_pledge_number is an input parm:
BEGIN
SELECT /*+ INDEX (pp) */ SUM(pp.prim_pledge_amount)
INTO return_amount
FROM
primary_pledge pp
WHERE
-- Get total if multiple allocations
pp.prim_pledge_number IN
(SELECT pc.pledge_number
FROM pledge_codes pc
WHERE pc.pledge_code_type = 'M'
AND pc.pledge_code = 'AC'
AND lpad(pc.pledge_comment,10,'0') = i_pledge_number)
-- Get total if single allocation
OR pp.prim_pledge_number = i_pledge_number;
RETURN return_amount;
END;
If I comment out either half of the OR statement (either the subquery or the pp.prim_pledge_number = i_pledge_number half) the function returns a value in .02 seconds. If I leave the OR in, it takes 2.764 seconds to execute?? Can someone please show me a better way (faster) to do this? I tried using nvl() around the subquery but couldn't get it to compile.
ThanksThese things are difficult to diagnose remotely, but here is something you can try....
SELECT */ SUM(pp.prim_pledge_amount)
INTO return_amount
FROM primary_pledge pp
WHERE pp.prim_pledge_number IN (SELECT pc.pledge_number
FROM pledge_codes pc
WHERE pc.pledge_code_type = 'M'
AND pc.pledge_code = 'AC'
AND lpad(pc.pledge_comment,10,'0') = i_pledge_number
UNION ALL
SELECT i_pledge_number FROM dual)
RETURN return_amount;
END;If that doesn't do anything (and it might well not) there are a large number of different ways we can recast this query. To save us further guessing please give us more details: execution plans, database version number, volumetrics.
Cheers, APC
Maybe you are looking for
-
Display total dmbtr according to mat type and month wise
hi all, i want to display total dmbtr according to mat type and month wise. like month mat.type total_dmbtr jan 2008 fert xxxxxxxxxx jan 2008 mcfe yyyyyyyy feb 2008 fert mmmmm
-
SAPGUI - 'Signature Design', being in different systems, QA, Tst, Prod
With "Enjoy", I could set my Dev, QA, Tst & Prod to different colors so I can quickly tell what system I am in without looking in lower right corner. I saw a note saying with Signature Design UI, you can't change the color scheme. Is this still true
-
Greetings fellow developers, new and old. I am a new developer and even newer to CR. I need help setting up CR XI for my company. Here is my question. In general, is CR installed on the local developer's machines for report development and then pu
-
CS6 installing trouble on my 2nd tablet PC
Hi, I bought Cintiq Companion (graphic tablet with window 8). And tring to install CS6 from my disk. Messege "serial number you provided is valid, but a qualifying product could not be found on this computer" apper and I can't complete installation.
-
Client Push on Windows 7 x86 with IE9 open.
I everyone, I need to validate something. I am currently deploying SCCM 2012 R2 for a client of mine. They are using mainly Windows 7 with SP1 x86 with IE9 installed. When doing client push from the console or installing any SCCM agent update, we ar