Populating Tables in Access - ms-access-2013

I'm new to Access and trying to create a simple Access tool where one Table gets data from another Table.
For example I have Table 1 with a Qty for each unique ID. Table 2A now needs to retrieve data from Table 1 based on the row's ID to finally look like Table 2B.
Table 1: | Table 2A: | Table 2B:
-----------------------------------------------------------
ID Name Qty | ID Name Qty | ID Name Qty
1 One 19 | 1 One | 1 One 19
2 Two 21 | 3 Three | 3 Three 10
3 Three 10 | 1 One | 1 One 19
4 Four 26 | 4 Four | 4 Four 26
5 Five 20 | 4 Four | 4 Four 26
I took a look at the "Lookup Wizard" but all the forums I've been to advises not to use it. Can anyone please advise on how to do this in Access in the simplest way.

Related

Is there a way to cache and filter a table locally in PL SQL?

I’m faced with having to process a table in ORACLE 11g, that contains around 5 million records. These records are speed limits along a divided highway. There is a SpeedLimitId, HighwayId and a from mile post and to mile post to depict the area that the speed limit is applied to. Currently all the records are only on one side of the divided highway and the records need to be processed to also apply them to the other side. There is a measure equation table that lets us know which range of measure on one side of the highway equal a range of measure on the other side of the highway. This allows us to calculate the measure that the speed limit event will be on the other side by calculating the percentage of the measure value in the range on measure and then finding that same percentage of the range on the opposing side. The speed limit record can be contained to one measure equation record or it can cross several of them. Base on the information in the speed limit table and the measure equation, one or more records need to be inserted into a third table.
SPEED_LIMIT
+--------------+-----------+--------------+------------+------------+-------+
| SpeedLimitId | HighwayId | FromMilePost | ToMilePost | SpeedLimit | Lane |
+--------------+-----------+--------------+------------+------------+-------+
| 1 | 75N | 115 | 123 | 60 | South |
+--------------+-----------+--------------+------------+------------+-------+
MEASURE_EQUATION
+------------+----------------+-----------+---------+-------+----------------+-----------+---------+-------+------------------+
| EquationId | NorthHighwayId | NFromMile | NToMile | NGain | SouthHighwayId | SFromMile | SToMile | SGain | IsHighwayDivided |
+------------+----------------+-----------+---------+-------+----------------+-----------+---------+-------+------------------+
| 1 | 75N | 105 | 120 | 15 | 75S | 100 | 110 | 10 | No |
| 2 | 75N | 120 | 125 | 5 | 75S | 110 | 125 | 15 | Yes |
| 3 | 75N | 125 | 130 | 5 | 75S | 125 | 130 | 5 | No |
+------------+----------------+-----------+---------+-------+----------------+-----------+---------+-------+------------------+
Depending on information in the SPEED_LIMIT and MEASURE_EQUATION table there will be a need to insert at least one but can be as many as three records in a third table. There are a dozen or so different scenarios that can take place as a result of different values in the fields.
Using the above data you can see that the SpeedLimitId 1 is noted as being on the south side of the highway, but it is currently on the north side and that it also spans the 2 equation records with the ids of 1 and 2. In this case it spans two measure ranges as a single roadway splits off and becomes divided highway. We need to split the original records into two events and add them to third processing table and calculate the new measure for the south bound lane.
SPEED_LIMIT_PROCESSING
+--------------+-----------+-------+----------+--------+
| SpeedLimitId | HighwayId | LANE | FromMile | ToMile |
+--------------+-----------+-------+----------+--------+
| 1 | 75N | North | 115 | 120 |
| 1 | 75S | South | 110 | 119 |
+--------------+-----------+-------+----------+--------+
The methodology to calculate the measure on the south bound lane is as follows:
+--------------------+----------------------------+-----------------------------+
| | From Measure Translation | To Measure Translation |
+--------------------+----------------------------+-----------------------------+
| Event Measure as % | ((120 – 120)/5) * 100 = 0% | ((123 – 120)/5) * 100 = 60% |
| Offset Measure | ((15 * 0) / 100 = 0 | ((15 * 60) / 100) = 9 |
| Translated Measure | 110 + 0 = 110 | 110 + 9 = 119 |
+--------------------+----------------------------+-----------------------------+
My concern is to do this in the most efficient way possible. The idea would be to loop through each record in the SPEED_LIMIT table, select the corresponding records in the measure equation table and then based on information from those 2 tables I would insert records into a 3rd table. In order to limit PL/SQL context switches I planned on using "BULK COLLECT and FORALL” statements to query the event table and to run the insert statements, this would allow me to do things in batches. The missing component is how to get the corresponding records from the MEASURE_EQUATION table without having to do a sql query for every record loop in the SPEED_LIMIT table. The MEASURE_EQUATION only has about 700 records in it, so I was wondering if there is a way I can cache it in PL SQL and then filter it to the appropriate records for the current SPEED_LIMIT record.
As you can probably gleamed from my question, I’m fairly new at PL SQL and ORACLE in general, so maybe I’m going about it in the completely wrong way.

Oracle not use extra indexes when there's an ORDER BY

I'm playing with Oracle 12 and indexes...
In a query like this:
SELECT a, b, c FROM table WHERE col1 = val1 AND col2 = val2 ORDER BY id DESC
(where id is the primary key of the table), Oracle always uses the index on the primary key.
So even if I create an index on the columns col1 and col2, since there's the ORDER BY statement, it doesn't use the index.
So can I infer that this is a general rule? Should I never put extra indexes in case all my queries contains "ORDER BY ID" ?
Here is my table structure:
ID NUMBER GENERATED ALWAYS AS IDENTITY NOCACHE ORDER,
USERNAME VARCHAR2(30 CHAR)
TYPE_A CHAR(1 BYTE)
TYPE_B CHAR(1 BYTE)
CREATED DATE
UPDATED DATE
ALTER TABLE my_table
ADD CONSTRAINT my_table_pk
PRIMARY KEY (ID)
USING INDEX TABLESPACE XXX;
On the table I perform only this query:
SELECT id, USERNAME, TYPE_A, TYPE_B, CREATED FROM table
where username = 'MYUSER'
AND created >= TO_DATE('2016-01-01','YYYY-MM-DD')
AND created <= TO_DATE('2016-06-30','YYYY-MM-DD')
AND TYPE_A = 1
order by ID desc;
One index: on pk (ID) (automatically created by oracle)
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 384 | 1 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| table | 2 | 384 | 1 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN DESCENDING| INDEX_PK | 10 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------
Two indexes: first on pk and second on (USERNAME, CREATED, TYPE_A)
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 384 | 1 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| table | 2 | 384 | 1 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN DESCENDING| INDEX_PK | 10 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------
So the second index seems to be useless.
By the way If i remove the ORDER BY statement, Oracle uses the second index on USERNAME, CREATED, TYPE_A.
Thanks all!
Let me just give you a counterexample which shows that there are cases where Oracle will use the second index.
SQL> create table tab (
2 ID NUMBER GENERATED ALWAYS AS IDENTITY NOCACHE ORDER,
3 USERNAME VARCHAR2(30 CHAR),
4 TYPE_A CHAR(1 BYTE),
5 TYPE_B CHAR(1 BYTE),
6 CREATED DATE,
7 UPDATED DATE
8 )
9 /
Table created.
SQL> alter table tab add constraint tab_pk primary key (id) using index
2 /
Table altered.
SQL> create index SECOND_IDX on tab(username, created, type_a)
2 /
Index created.
SQL> insert into tab(username, type_a, type_b, created)
2 select 'OTHER_USER', '2', '2', date '2015-06-01'
3 from all_objects, all_objects where rownum <= 1e5;
100000 rows created.
SQL>
SQL> update tab
2 set username = 'MYUSER',
3 created = DATE '2016-06-01',
4 type_a = '1'
5 where id = 50000;
1 row updated.
SQL> commit;
Commit complete.
SQL> begin
2 dbms_stats.gather_table_stats(ownname => USER,
3 tabname => 'TAB',
4 estimate_percent => 100,
5 method_opt => 'FOR ALL INDEXED COLUMNS'
6 );
7 end;
8 /
PL/SQL procedure successfully completed.
SQL>
SQL> set autotrace traceonly exp
SQL>
SQL> SELECT id, USERNAME, TYPE_A, TYPE_B, CREATED FROM tab
2 where username = 'MYUSER'
3 AND created >= TO_DATE('2016-01-01','YYYY-MM-DD')
4 AND created <= TO_DATE('2016-06-30','YYYY-MM-DD')
5 AND TYPE_A = '1'
6 order by ID desc;
Execution Plan
----------------------------------------------------------
Plan hash value: 3658386757
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 29 | 5 (20)| 00:00:01 |
| 1 | SORT ORDER BY | | 1 | 29 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| TAB | 1 | 29 | 4 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | SECOND_IDX | 1 | | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
In this case the reason to use the second index is the extremely high selectivity (one row out of 100000).
Well, in short answer - no, but we can't give you a general rule, because every time will be different as to a lot of different variable. For more specific answer you should include an explain plan of this query, and we'll have a better picture on why it doesn't use the index.
Oracle will know to use this index as long as ID column will be specified first .
You shouldn't add unnecessary indexes for selects that will only occur once in a lot of time or those that are slow, but not too slow. You should only add indexes related to the most common selects/updates that occurs on this table.
If a select with filters on col1 and col2 is repeatedly , then most likely(again, I don't know what other processes you are doing on this table) an index on all 3 columns will be better :
(ID,Col1,Col2)

Why oracle CHOOSE INDEX RANGE SCAN over FAST FULL INDEX SCAN

I have read some documentation about indexes, I did some examples and now I have some doubts.
I create a table and insert random values, (A column has unique values) column A NOT NULL
I create an index on A, B, C. (B-TREE)
SELECT COUNT(*) FROM DEMO_FULL_INDEX_SCAN;
=1000
SELECT * FROM DEMO_FULL_INDEX_SCAN;
A B C D E F
---------- ---------- ---------- ---------- ---------- ----------
1 7 109 1 1 1
2 12 83 2 2 2
3 21 120 3 3 3
4 13 74 4 4 4
5 2 1 5 5 5
...
Documentation says when all query values are in the index, the values are gathered from index (INDEX FAST FULL SCAN), but here optimizer is choosing another operation.
EXPLAIN PLAN FOR
SELECT A,B,C FROM DEMO_FULL_INDEX_SCAN WHERE A = 1;
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
|* 1 | INDEX RANGE SCAN | FIS_01 | | | |
--------------------------------------------------------------------
I have to specify a hint to optimizer choose INDEX FAST FULL SCAN (but i dont know why i have to specify it)
EXPLAIN PLAN FOR
SELECT /*+ INDEX_FFS(DEMO_FULL_INDEX_SCAN FIS_01) */A,B,C FROM DEMO_FULL_INDEX_SCAN WHERE A = 1;
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 2 |
|* 1 | INDEX FAST FULL SCAN| FIS_01 | 1 | 11 | 2 |
--------------------------------------------------------------------
By the other hand ,this examples shows what oracle documentation says.
When there is a value in the query that is not in the index, this value is accessed by TABLE ACCESS BY INDEX ROWID
EXPLAIN PLAN FOR
SELECT D FROM DEMO_FULL_INDEX_SCAN WHERE A = 800;
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Co
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |
| 1 | TABLE ACCESS BY INDEX ROWID| DEMO_FULL_INDEX_SCAN | | |
|* 2 | INDEX RANGE SCAN | FIS_01 | | |
--------------------------------------------------------------------------------
My question is ,in the first example why Oracle CHOOSE INDEX RANGE SCAN over FAST FULL INDEX SCAN.
You're performing an INDEX RANGE SCAN because of the WHERE clause of your SQL statement:
select a,b,c from demo_full_index_scan where a = 1;
I'm assuming here that you don't have a unique index on A despite the uniqueness of the column, i.e. your table DDL is something like this:
create table demo_full_index_scan (
a number
, b number
, c number
, d number
);
create index i_demo_full_index_scan on demo_full_index_scan (a, b, c);
As you don't have a UNIQUE index Oracle can't know with certainty that the values in A will always be unique; however, Oracle does know that A is the first column in the index and can find this value in the range of values available in the index.
If your WHERE clause were to attempt to filter based on the column C you would perform an INDEX FULL SCAN as C exists in the index, so you don't need to access the table, but it is not the first column in the index:
explain plan for select a,b,c from demo_full_index_scan where c = 1;
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 1 (0)| 00:00:01 |
|* 1 | INDEX FULL SCAN | I_DEMO_FULL_INDEX_SCAN | 1 | 39 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

Oracle query to list all parents before children

I have a table which has child#, parent# like the following :
child# | parent#
------------------
10 | NULL
20 | NULL
2 | 1
1 | 10
50 | 10
6 | 5
5 | 2
There is no ordering of numbers, i.e. 1 can be parent of 10 and 10 can be parent of 20.
I want an ORACLE SQL query which lists all parents first, followed by their children.
I want a temporary table like following:
child# | parent#
----------------
10 | NULL
20 | NULL
1 | 10
2 | 1
50 | 10
5 | 2
I want to traverse this temporary table and process each rows, so for that I need to make sure parent is listed before the children rows.
select level,child,parent
from your_table
start with t2.parent is null
connect by prior t2.child = t2.parent
order by level
OUTPUT:
LEVEL CHILD PARENT
1 10 (null)
1 20 (null)
2 1 10
2 50 10
3 2 1
4 5 2
5 6 5
Link to fiddle

How to utilize TABLE ACCESS BY INDEX ROWID

I have a problem with a query that uses a FULL TABLE SCAN.
When this query runs on our UAT env, it uses a TABLE ACCESS BY INDEX ROWID, but in prod
it uses FULL TABLE SCAN. UAT runs much better than PROD.
We have the same tables and indexes structure in prod and uat.
I already tried rebuilding and recreating the indexes but the same explain plan is used.
Table and indexes statics were also updated.
Can you help me to make this query use INDEX access instead of FUll table access?
Please see below the explain plan of our prod and uat.
EXPLAIN PLAN PROD
=====================================================================
SQL> explain plan for
SELECT ASV_ODC_BRANCH.CODE, ASV_ODC_BRANCH.DESCRIPTION, ASV_ODC_BRANCH.BRSTN, DEB.VIEW_DORMANT.ACCTNO AS DORMANT_ACCT,
DEB.VIEW_DORMANT.SHORTNAME AS DORMANT_NAME, DEB.VIEW_DORMANT.OPID_ENTRY, DEB.CUSTOMER.CUSTOMERNO,
DEB.CUSTOMER.TIME_STAMP_ENTRY
FROM ASV_ODC_BRANCH, DEB.VIEW_DORMANT, DEB.CUSTOMER
WHERE trim(ASV_ODC_BRANCH.CODE) = decode(SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 3, 1) || SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 7, 1), ’29’,
SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 4, 3), SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 3, 3)) AND
DEB.VIEW_DORMANT.ACCTNO = DEB.CUSTOMER.CUSTOMERNO AND (DEB.VIEW_DORMANT.ACCTNO = :Xacct)
ORDER BY ASV_ODC_BRANCH.CODE, DORMANT_ACCT;
Explained.
PLAN_TABLE_OUTPUT | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
| 0 | SELECT STATEMENT | | 3 | 489 | 3601 (2)|
| 1 | SORT ORDER BY | | 3 | 489 | 3601 (2)|
| 2 | HASH JOIN | | 3 | 489 | 3600 (2)|
| 3 | MERGE JOIN CARTESIAN | | 1 | 90 | 3595 (2)|
| 4 | NESTED LOOPS | | 1 | 66 | 3592 (2)|
| 5 | **TABLE ACCESS FULL** | ACCOUNT | 1 | 56 | 3590 (2)|
| 6 | TABLE ACCESS BY INDEX ROWID| EXTENSION1 | 1 | 10 | 2 (0)|
| 7 | INDEX UNIQUE SCAN | PKEXT10 | 1 | | 1 (0)|
| 8 | BUFFER SORT | | 1 | 24 | 3593 (2)|
| 9 | TABLE ACCESS BY INDEX ROWID| CUSTOMER | 1 | 24 | 3 (0)|
| 10 | INDEX RANGE SCAN | UXCUST1 | 1 | | 2 (0)|
| 11 | TABLE ACCESS FULL | ASV_ODC_BRANCH | 334 | 24382 | 5 (0)|
**EXPLAIN PLAN UAT**
======================================================================================
SQL> explain plan for
SELECT ASV_ODC_BRANCH.CODE, ASV_ODC_BRANCH.DESCRIPTION, ASV_ODC_BRANCH.BRSTN, DEB.VIEW_DORMANT.ACCTNO AS DORMANT_ACCT,
DEB.VIEW_DORMANT.SHORTNAME AS DORMANT_NAME, DEB.VIEW_DORMANT.OPID_ENTRY, DEB.CUSTOMER.CUSTOMERNO,
DEB.CUSTOMER.TIME_STAMP_ENTRY
FROM ASV_ODC_BRANCH, DEB.VIEW_DORMANT, DEB.CUSTOMER
WHERE trim(ASV_ODC_BRANCH.CODE) = decode(SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 3, 1) || SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 7, 1), ’29’,
SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 4, 3), SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 3, 3)) AND
DEB.VIEW_DORMANT.ACCTNO = DEB.CUSTOMER.CUSTOMERNO AND (DEB.VIEW_DORMANT.ACCTNO = :Xacct)
ORDER BY ASV_ODC_BRANCH.CODE, DORMANT_ACCT;
Explained.
SQL> /
PLAN_TABLE_OUTPUT
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
| 0 | SELECT STATEMENT | | 5 | 5930 | 19 (11)|
| 1 | SORT ORDER BY | | 5 | 5930 | 19 (11)|
| 2 | HASH JOIN | | 5 | 5930 | 18 (6)|
| 3 | MERGE JOIN CARTESIAN | | 2 | 2220 | 12 (0)|
| 4 | NESTED LOOPS | | 1 | 1085 | 9 (0)|
| 5 | **TABLE ACCESS BY INDEX ROWID**| ACCOUNT | 1 | 57 | 7 (0)|
| 6 | INDEX SKIP SCAN | UXACCT2 | 1 | | 6 (0)|
| 7 | TABLE ACCESS BY INDEX ROWID| EXTENSION1 | 1 | 1028 | 2 (0)|
| 8 | INDEX UNIQUE SCAN | PKEXT10 | 1 | | 1 (0)|
| 9 | BUFFER SORT | | 1 | 25 | 10 (0)|
| 10 | TABLE ACCESS BY INDEX ROWID| CUSTOMER | 1 | 25 | 3 (0)|
| 11 | INDEX RANGE SCAN | UXCUST1 | 1 | | 2 (0)|
| 12 | TABLE ACCESS FULL | ASV_ODC_BRANCH | 336 | 25536 | 5 (0)|
The difference is in
EXPLAIN PLAN PROD
| 5 | **TABLE ACCESS FULL** | ACCOUNT | 1 | 56 | 3590 (2)|
EXPLAIN PLAN UAT
| 5 | **TABLE ACCESS BY INDEX ROWID**| ACCOUNT | 1 | 57 | 7 (0)|
| 6 | INDEX SKIP SCAN | UXACCT2 | 1 | | 6 (0)|
How does it work?
Rather than restricting the search path using a predicate from the statement, Skip Scans are initiated by probing the index for distinct values of the prefix column. Each of these distinct values is then used as a starting point for a regular index search. The result is several separate searches of a single index that, when combined, eliminate the affect of the prefix column. Essentially, the index has been searched from the second level down.
The optimizer uses statistics to decide if a skip scan would be more efficient than a full table scan.
Optimizer considers his as an advantage over a FTS because
It reduces the number of indexes needed to support a range of queries. This increases performance by reducing index maintenance and decreases wasted space associated with multiple indexes.
The prefix column should be the most discriminating and the most widely used in queries. These two conditions do not always go hand in hand which makes the decision difficult. In these situations skip scanning reduces the impact of makeing the "wrong" decision.
You can consider the following
Check the optimizer mode across the environments.
Gather stats on all the tables used in the query. For example, if a table has not been analyzed since it was created, and if it has less than DB_FILE_MULTIBLOCK_READ_COUNT blocks under the high water mark, then the optimizer thinks that the table is small and uses a full table scan. Review the LAST_ANALYZED and BLOCKS columns in the ALL_TABLES table to examine the statistics.
Though your environment is similar and code is same, optimizer is going to check on the fly and choose the best available method. So do your UAT with same data setup. Since it is a UAT (almost a preproduction in most o the companies), it should be the closest to production in terms of size.
From what I can see, table DEB.VIEW_DORMANT is a view on tables ACCOUNT and EXTENSION1, and you'd like to use index UXACCT2 from the former. I guess a hint inside this request should allow you to do what you want, something like:
SELECT /*+ INDEX(D UXACCT2) */ ASV_ODC_BRANCH.CODE,
...
FROM ASV_ODC_BRANCH, DEB.VIEW_DORMANT D, DEB.CUSTOMER
...
PS: if this is a query you manage (not generated by any high-level software), I suggest you use aliases for your table as I did, that makes queries so much more readable...
Can I help you to make it a INDEX-ACCESS instead of a FTS? Probably...
Do you really want that? - Probably NOT
Why is the database behaving differently? Because you operate on different data - As your sample shows, the query returns a different number of rows, so I don't even have to ask if your production and test-data is the same. If you have different data (different amounts or different values in indexed columns) you Database-Stats will be different, your indexes will look different and so the optimizer will come to a different query-plan!
What should you do? Make sure all you indexes are up to date, your partitions are sanely arranged, all you database-stats are up-to-date and no strange tuning-settings are in place ( query-plans, environment settings...) Then the optimizer will in most cases find the best plan - and in many cases a full-table-scan is the FASTER alternative.
But if you measure the times and the optimizer clearly takes the wrong path, although it has accurate table-stats, you should file a bug-report with oracle.
If you have other reasons for wanting the optimizer to do indexed-access:
If you cannot enter an Optimizer-HINT like Emmanuel offered, you can try Profiles or Baselines, which offer nice tuning possibilities. You can write your own statement, with different WHERE-Predicates until you get a plan with index-access and use this as an SQL-Profile and link this profile to the original statement which will then use the same query-plan.

Resources