Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Randy.

Asked: August 07, 2002 - 9:56 am UTC

Last updated: April 04, 2007 - 11:26 am UTC

Version: 8.1.7

Viewed 1000+ times

You Asked

is there just ONE space between words or is it totally free form? Actually, it's a totally free form. Thanks for your response.



Hi Tom,
I have a sql statement:
Select Document_title ||'or'|| Document_title
from atas_query_v

I understand this just repeats the column twice using 'OR' in between. What I'm looking for is a way to have the 'OR' placed between each word for that column. Is that possible to accomplish in a SQL output? I know this sounds like a strange request, but I need to use the 'OR' between each keyword in my Oracle Forms application. Users have one text item which queries the DB using the Intermedia text function. If they enter two keywords it searches on the exact keyword. I want to use the OR function between keywords so more results are returned. I hope this makes sense...

Thanks in advance,
Randy


and Tom said...

We'll have to write a stored procedure to do that. Here is the code I use on asktom to process the search string you guys type in:

create or replace package delimited
as
function word( p_str in varchar2,
p_n in varchar2,
p_enclosed_by in varchar2 default '''',
p_separated_by in varchar2 default ',' )
return varchar2;

function context_query( p_search_str in varchar2,
p_sep in varchar2 default 'OR' )
return varchar2;

pragma restrict_references( word, WNDS, RNDS );
end;
/

create or replace package body delimited
as
type vcArray is table of varchar2(2000) index by binary_integer;

g_words vcArray;
g_empty vcArray;
g_last_string varchar2(4096);

function de_quote( p_str in varchar2,
p_enc_by in varchar2 )
return varchar2
is
begin
if ( p_enc_by is null )
then
return p_str;
else
return replace( ltrim( rtrim( p_str, p_enc_by ), p_enc_by ),
p_enc_by||p_enc_by, p_enc_by );
end if;
end de_quote;


procedure parse( p_str in varchar2,
p_delim in varchar2,
p_sep in varchar2 )
is
l_n number default 1;
l_in_quote boolean default FALSE;
l_ch char(1);
l_len number default nvl(length( p_str ),0);
begin
if ( l_len = 0 ) then
return;
end if;

g_words := g_empty;
g_words(1) := NULL;

for i in 1 .. l_len loop
l_ch := substr( p_str, i, 1 );
if ( l_ch = p_delim ) then
l_in_quote := NOT l_in_quote;
end if;
if ( l_ch = p_sep AND NOT l_in_quote ) then
l_n := l_n + 1;
g_words(l_n) := NULL;
else
g_words(l_n) := g_words(l_n)||l_ch;
end if;
end loop;

for i in 1 .. l_n loop
g_words(i) := de_quote( g_words(i), p_delim );
end loop;
end parse;


function word( p_str in varchar2,
p_n in varchar2,
p_enclosed_by in varchar2 default '''',
p_separated_by in varchar2 default ',' )
return varchar2
is
begin
if ( g_last_string is NULL or p_str <> g_last_string ) then
g_last_string := p_str;
parse( p_str, p_enclosed_by, p_separated_by );
end if;
return g_words( p_n );
exception
when no_data_found then return NULL;
end;

function context_query( p_search_str in varchar2,
p_sep in varchar2 default 'OR' )
return varchar2
is
l_temp_value varchar2(1000);
l_return_value varchar2(1000) := NULL;
l_start_token number := 1;
l_in_token boolean := FALSE;
l_sep varchar2(20);
begin
if nvl(length(p_search_str),0) = 0 then
return NULL;
end if;
--
l_temp_value := trim(replace( lower(p_search_str), ':', ' '));
l_temp_value := trim(replace( l_temp_value, ';', ' '));
l_temp_value := trim(replace( l_temp_value, '"', ' '));
l_temp_value := trim(replace( l_temp_value, ':'',', ' '));
l_temp_value := trim(replace( l_temp_value, '(', ' '));
l_temp_value := trim(replace( l_temp_value, ')', ' '));
l_temp_value := trim(replace( l_temp_value, '!', ' '));
l_temp_value := trim(replace( l_temp_value, '&', ' '));
l_temp_value := trim(replace( l_temp_value, '+', ' '));
l_temp_value := trim(replace( l_temp_value, '-', ' '));
l_temp_value := trim(replace( l_temp_value, ',', ' '));
l_temp_value := trim(replace( l_temp_value, ' and ', ' ' ));
l_temp_value := trim(replace( l_temp_value, ' or ', ' ' ));
--
if length(l_temp_value) > 0 then
l_in_token := TRUE;
end if;
--
for i in 1..length(l_temp_value) loop
if substr(l_temp_value,i,1) = ' ' then
if l_in_token = TRUE then
l_return_value := l_return_value || l_sep || ' {' ||
substr(l_temp_value,l_start_token, i-l_start_token) ||
'}' || ' ';
l_sep := p_sep;
l_in_token := FALSE;
end if;
elsif l_in_token = FALSE then
l_in_token := TRUE;
l_start_token := i;
end if;
end loop;
if l_in_token = TRUE then
l_return_value := l_return_value || l_sep || ' {' ||
substr(l_temp_value,l_start_token) || '} ';
end if;
return trim(l_return_value);
end;

end delimited;
/



You use it like this:


ops$tkyte@ORA817DEV.US.ORACLE.COM> select delimited.context_query( 'how now brown cow' ) from dual;

DELIMITED.CONTEXT_QUERY('HOWNOWBROWNCOW')
-----------------------------------------------------------------------------------------------------------------------------------
{how} OR {now} OR {brown} OR {cow}

ops$tkyte@ORA817DEV.US.ORACLE.COM> select delimited.context_query( 'how now brown cow', 'AND' ) from dual;

DELIMITED.CONTEXT_QUERY('HOWNOWBROWNCOW','AND')
-----------------------------------------------------------------------------------------------------------------------------------
{how} AND {now} AND {brown} AND {cow}





Rating

  (7 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

A reader, July 09, 2003 - 9:55 am UTC


Trim heading

SHGoh, November 19, 2004 - 10:20 pm UTC

Hi Tom,

   Is there any setting require to address the following issue ? Thanks in advance.

Oracle8i Enterprise Edition Release 8.1.7.4.0 - Production
With the Partitioning option
JServer Release 8.1.7.4.0 - Production

SQL> select substr(host_name,1,4) from v$instance;

SUBSTR(HOST_                        <--- Show
------------
ever              

SUBS                                <--- Expected result
----
ever  

When I check on version 8.1.7.2, it looks fine.

Oracle8i Enterprise Edition Release 8.1.7.2.0 - Production
With the Partitioning option
JServer Release 8.1.7.2.0 - Production

SQL> select substr(host_name,1,4) from v$instance;

SUBS                           <--- Return result
----
e10k

Thanks
Goh
 

Tom Kyte
November 20, 2004 - 8:13 am UTC

show parameter cursor_sharing

you have cursor sharing set to force -- making your substr(host_name,1,4) become substr( host_name, :sys_bv0, :sys_bv1 ) -- meaning we no longer know "4"



ops$tkyte@ORA9IR2> select substr(user,1,1) from dual d1;
 
S
-
O
 
ops$tkyte@ORA9IR2> alter session set cursor_sharing=force;
 
Session altered.
 
ops$tkyte@ORA9IR2> select substr(user,1,1) from dual d2;
 
SUBSTR(USER,1,1)
------------------------------
O
 
ops$tkyte@ORA9IR2>
 

cursor_sharing doesn't help

Goh, November 23, 2004 - 3:46 am UTC

Hi Tom,

    Appreciate your help but it still can't work in Oracle 8.1.7. Any more clue? Thanks

SQL> show parameter cursor

NAME                                 TYPE    VALUE
------------------------------------ ------- ------------------------------
cursor_sharing                       string  EXACT
cursor_space_for_time                boolean FALSE
open_cursors                         integer 4000
session_cached_cursors               integer 0
SQL> select substr(host_name,1,4) from v$instance;

SUBSTR(HOST_
------------
ever

SQL> alter session set cursor_sharing=force;

Session altered.

SQL>  select substr(host_name,1,4) from v$instance;

SUBSTR(HOST_NAME,1,4)
--------------------------------------------------------------------------------
ever

SQL>
 

Tom Kyte
November 23, 2004 - 7:15 am UTC

oh, I see, you have a multi-byte character set if it wasn't cursor sharing.

check out your NLS characterset in the database in each -- what are they.

NLS_CHARACTERSET

shgoh, November 24, 2004 - 2:45 am UTC

Hi Tom,

Ya, the NLS_CHARACTERSET setting is different for both server. One is US7ASCII (It works fine for substr) and the other is UTF8. Any advice on how to resolve this as few reports encounter the formatting problem. Besides recreate control file with US7ASCII format, any other method. Thanks for your help.

Rgd
Goh

Tom Kyte
November 24, 2004 - 7:24 am UTC

you cannot "recreate the controlfile" the entire database would have to be unloaded, recreated and reloaded to go from utf8 to us7ascii

you have made a major huge, really large change in your application. you'll need to fix your application now - what used to take 40bytes might take 60, 70, 80 or more bytes. report formatting is just the tip of the iceberg.

why did you make such a large huge big change? without testing it?

Thanks for the information

shgoh41, November 25, 2004 - 12:38 am UTC

Dear Tom,

   Thanks for the advice. I have no mean to change the CHARSET at the moment. I have found out any method for this issue. instead of using substr(host_name,1,4), I use the following method.

SQL> set wrap off
SQL> column host_name format a4
SQL> /

HOST
----
ever

     Thanks for all the help.

Rgds
Goh 

I would like to see the latest delimited package used on AskTom.

Ian Matyssik, November 29, 2005 - 3:18 am UTC

Hello,

Could you please point me in the direction of the latest delimited package used on AskTom.



Tom Kyte
November 29, 2005 - 9:59 am UTC

this one is a good start.

</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:11471734233362 <code>

is my "current" one.

sql output file query !!!

parag j patankar, April 04, 2007 - 10:19 am UTC

Hi,

I am trying to execute following query in aix. My objective is to create 0 byte spool file if my query is returning no rows.

query

sqlplus -s / <<EOF
set pagesize 0
set feedback off
set echo off
set trimspool on
spool $A2_IMP/toto.txt

select
intraday||actnum||v00090||a5500||v00230||amt||trandt||valuedt||utr_number||sender_ifsc||ref1||ref2||dealercd||salesorg||tr
antype||r1
from vtvz232
order by utr_number
/
spool off;
EOF

where there are no rows, it is creating 1 byte output file. Why so ? I want 0 byte file to be get generated. ( nothing inside )

-rw-rw-r-- 1 test test 1 Apr 04 20:24 toto.txt
{dev}/usr/dev1/data1/imp

Note :

1/ This view is created union with dual
2/ Output file with 1 byte is not always the case with same view also>

thanks & regards
paragjp
Tom Kyte
April 04, 2007 - 11:26 am UTC

because sqlplus is just a simple command line tool - it created a space, because it wanted to.

sorry - it is what it is.


but in any case, I do not reproduce on linux - but I would not rely on this anyway, it is just a command line reporting tool.

[tkyte@desktop ~]$ cat test.sh
#!/bin/bash

$ORACLE_HOME/bin/sqlplus -s /nolog << EOF
 connect /
 set pagesize 0
 set feedback off
 set echo off
 set trimspool on
 spool toto.txt
 select object_name||object_type||created||last_ddl_time||object_id from all_objects where 1=0;
 spool off;
 exit
EOF

ls -l toto.txt
[tkyte@desktop ~]$ ./test.sh
-rw-rw-r--  1 tkyte tkyte 0 Apr  4 12:24 toto.txt
[tkyte@desktop ~]$


maybe you want to exit with return codes and erase the spool file or something more predicable

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library