how to optimize contains in oracle sql query - oracle

I need to use oracle Contains function in a query like this:
select *
from iindustrialcasehistory B
where CONTAINS(B.ItemTitle, '%t1%') > 0 OR
CONTAINS(B.ItemTitle, '%t2%') > 0
I've defined context index for ItemTitle column, but execution time is about a minute!whereas i need it to be executed in less than a second!
thanks for any execution time reduction guide in advanced!

Contains searches for all appearances of substring in a string, that’s why better use instr() instead, because it searches only first occurrence of substring, what's supposed to be faster.
Then you can build index for function Instr(B.ItemTitle,'t1') + Instr(B.ItemTitle,'t1').
And use this function value > 0 in a query after that.
You can see more details about using index with instr function here.

Related

In Visual FoxPro, how does one incorporate a SUM REST command into a SCAN loop?

I am trying to complete a mortality table, using loops in Visual Foxpro. I have run into one difficulty where the math operation involves doing a sum of of all data in a column for the remaining rows - this needs to be incorporated into a loop. The strategy I thought would work, nesting a SUM REST function into the SCAN REST function, was not successful, and I haven't found a good alternative approach.
In FoxPro, I can successfully use the SCAN function as follows, say:
Go 1
Replace survivors WITH 1000000
SCATTER NAME oprev
SKIP
SCAN rest
replace survivors WITH (1 - oprev.prob) * oprev.survivors
SCATTER NAME oprev
ENDSCAN
(to take the mortality rates in a table and use it to compute number of survivors at each age)
Or, say:
Replace Yearslived WITH 0
SCATTER NAME oprev1
SKIP
SCAN rest
replace Yearslived WITH (oprev1.survivors + survivors) * 0.5
SCATTER NAME oprev1
ENDSCAN
In order to complete a mortality table I want to use the Yearslived and survivors data (which were produced using the SCANs above) to get life expectancy data as follows. Say we have the simplified table:
SURVIVORS YEARSLIVED LIFEEXP
100 0 ?
80 90 ?
60 70 ?
40 50 ?
20 30 ?
0 10 ?
Then each LIFEEXP record should be the sum of the remaining YEARSLIVED records divided by the corresponding Survivors record, i.e:
LIFEEXP (1) = (90+70+50+30+10)/100
LIFEEXP (2) = (70+50+30+10)/80
...and so on.
I attempted to do this with a similar SCAN approach - see below:
Go 1
SCATTER NAME Oprev2
SCAN rest
replace lifeexp WITH ((SUM yearslived Rest) - oprev2.yearslived) / oprev2.survivors
SCATTER NAME oprev2
ENDSCAN
But here I get the error message "Function name is missing)." Help tells me this is probably because the function contains too many arguments.
So I then also tried to break things down and first use SCAN just to get all of my SUM REST data, as follows:
SCAN rest
SUM yearslived REST
END SCAN
... in the hope that I could get this data, define it as a variable, and create a simpler SCAN function above. However, I seem to be doing something wrong here as well, as instead of getting all necessary sums (first the sum of rows 2 to end, then 3 to end, etc.), I only get one sum, of all the yearslived data. In other words, using the sample data, I am given just 250, instead of the list 250, 160, 90, 40, 10.
What am I doing wrong? And more generally, how can I create a loop in Foxpro that includes a function where you Sum up all remaining data in a specific column over and over again (first 2nd through last record, then 3rd through last record, and so on)?
Any help will be much appreciated!
TM
Well you are really hiding the important detail, your table's structure, sample data and desired output. Then it is mostly guess work which have a high chance of to be true.
You seem to be trying to do something like this:
Create Cursor Mortality (Survivors i, YearsLived i, LifeExp b)
Local ix, oprev1
For ix=100 To 0 Step -20
Insert Into Mortality (Survivors, YearsLived) Values (m.ix,0)
Endfor
Locate
Survivors = Mortality.Survivors
Skip
Scan Rest
Replace YearsLived With (m.Survivors + Mortality.Survivors) * 0.5
Survivors = Mortality.Survivors
Endscan
*** Here is the part that deals with your sum problem
Local nRecNo, nSum
Scan
* Save current recnord number
nRecNo = Recno()
Skip
* Sum REST after skipping to next row
Sum YearsLived Rest To nSum
* Position back to row where we started
Go m.nRecNo
* Do the replacement
Replace LifeExp With Iif(Survivors=0,0,m.nSum/Survivors)
* ENDSCAN would implicitly move to next record
Endscan
* We are done. Go first record and browse
Locate
Browse
While there are N ways to do this in VFP, this is one xbase approach to do that and relatively simple to understand IMHO.
Where did you go wrong?
Well, you tried to use SUM as if it were a function, but it is a command. There is SUM() function for SQL as an aggregate function but here you are using the xBase command SUM.
EDIT: And BTW in this code:
SCAN rest
SUM yearslived REST
ENDSCAN
What you are doing is, starting a SCAN with a scope of REST, in loop you are using another scoped command
SUM yearslived REST
This effectively does the summing on the REST of records and places the record pointer to bottom. Endscan further advances it to eof(). Thus it only works for the first record.

Query() function in Google Sheets yields stray value: Why, and how can I fix it?

I would like to run a query statement that adds a bullet (●) to each row of output.
Here is my sample data:
Here is the query:
=query($A$1:$B$3,"SELECT '●',A,B",0)
Here is the result:
Why does the first stray line appear in the output ["●"()], and how can I write the query so that it yields only rows 2, 3, 4 and not the first row?
Note that the actual data is much more complicated than this, so solving it with a filter or array does not work well. I need a query solution. And I'd really like to know why that first line is appearing in the first place.
Thanks for the help.
KLS
=QUERY($A$1:$B$3, "SELECT '●', A, B LABEL '●' ''", 0)
This assigns an empty string to the label for that column, thus eliminating the label row.

Understanding for-loop in XQuery to count occurrences in BaseX

I am trying to count the occurrences of an XML structure in BaseX.
declare variable $a := 0;
for $node in db:open("My_DB")/my/xml//path
$a += 1
return $a
When running this, BaseX returns the error: Incomplete FLWOR expression: expecting 'return'.
I know that I can count with this simple function:
count(db:open("My_DB")/my/xml//path)
But there are two reasons zhy I am trying to do this with a for loop:
I have been told by my supervisor that a for loop is faster
In the future I may want to execute more operations per hit (in the for loop)
So the question is: how can I count elements in a for loop with XQuery using BaseX.
As XQuery is a functional language, it’s not possible to reassign other values to a function. However, you can use fold-left to increment values in a loop:
fold-left(db:open("My_DB")/my/xml//path, 0, function($result, $curr) {
$result + 1
})
The execution time for count() depends on the implementation of XQuery. In BaseX, count() is usually much faster than a loop, because it can in many cases be accelerated by lookups in the database statistics.

Oracle NOT BETWEEN for string comparison does not give same result as <= and >=

Using Oracle 11gR2 Expression Edition.
My data looks like following
ordertype
---------
ZOCO
ZOSA
ZOST
We are trying to find out records where the column is not between a certain range of values.
If I run a query with <= and >= operators:
SELECT * FROM table where ordertype <= 'ZAAA' OR ordertype >= 'ZZZZ';
then I get 0 results. This is the right answer.
However, if I use NOT BETWEEN:
SELECT * FROM table where ordertype NOT BETWEEN 'ZAAA' AND 'ZZZZ';
, then it gives multiple hits.
My understanding is that both syntax should give the same result but they are not. What am I missing? Reason I want to use NOT BETWEEN because a lot of our existing code already has this syntax and I do not want to change it without understanding the reasons.
Thank you.
Thanks for all those who posted. I ran the queries again and after fixing the "OR" in the first query, the results are the same. I still have the question of why Oracle character sorting is not recognizing it as expected, but my question which is about difference between NOT BETWEEN and <> was a false alarm. I apologize for confusion.
SELECT * FROM table where ordertype <= 'ZAAA' AND ordertype >= 'ZZZZ';
No string can be <= 'ZAAA' and >= 'ZZZZ'.
You need to use a disjunction instead:
SELECT * FROM table where ordertype < 'ZAAA' OR ordertype > 'ZZZZ';
BTW, given that BETWEEN is inclusive, NOT BETWEEN is exclusive
This is a common pitfall. you have to remember the De Morgan's Laws:
not (A and B) is the same as (not A) or (not B)
Feel free to experiment with this simple live example to convince yourself that those results are quite coherent: http://sqlfiddle.com/#!4/d41d8/38326
That being said, the only way (I can see) for the string like ZOCO for not being between ZAAA and ZZZZ would be:
having some hidden character just behind the Z (i.e.: 'Z'||CHR(0)||'OCO')
or using a locale such as Z-something is actually considered as a different letter, with a collation order outside of the given range. I don't know if such locale exists, but for example, in Welch, LL is considered as a single letter that should be sorted after the plain L. See http://en.wikipedia.org/wiki/Alphabetical_order#Language-specific_conventions
or having homogplyphs such as 0, 𐒠 or О instead of O in your data.
If it's not between the values, it has to be either < OR >, not AND.
In the first query, you ask for the records that are at the same time less than 'ZAAA' and also greater than 'ZZZZ'. Of course, there is no such value that fullfills both requirements, hence zero records are returned.
In the second query, you ask for records, that are either less than 'ZAAA' or greater than 'ZZZZ' (ie not between those boundaries [not between...]). There is a possibility that such records exist, and as your select statement proves, there are indeed such records, that are returned by the statement.
Your understanding that both statements are same is incorrect. NOT BETWEEN is not evaluated the way you're thinking. It simply returns the results which fall outside evaluation of BETWEEN for the parameters.
IF you check Oracle documentation for BETWEEN, it says -
The value of
expr1 NOT BETWEEN expr2 AND expr3
is the value of the expression
NOT (expr1 BETWEEN expr2 AND expr3)

How to use checkbox values in code?

In my Oracle APEX application page I have checkbox item with multiple values. The source of checkbox is like this:
STATIC:One,Two,Apple
In page process I need to use the value from checkbox in PL/SQL code. As far as I understand I get colon separated values. Question is how to use those values and test if Value is One, then do this. If Two is checked as well, then do something more.
Depending on situation you can use:
Convert string with delimiter to table (you can use this as subquery):
select regexp_substr('1:2:3','[^:]+', 1, level) ID from dual
connect by regexp_substr('1:2:3', '[^:]+', 1, level) is not null;
ID
--
1
2
3
Check one value using instr:
where instr('1:2:3', '2') > 0
If value of the second argument of the function is contained inside the first argument - function returns its position, otherwise - 0.
For performance I prefer the INSTR function, e.g. INSTR(':'||:p_item||':',':Two:') > 0

Resources