ARRAY PROCESSING
Nirmal, May 13, 2003 - 6:17 pm UTC
Wow, wow, wow. That was a real response, I know the approch Stink, but i appricate you coming back so soon.
Well I forgot to mention that we are using prepared statement and bind variables and batch execute etc. But that was still not able to get near to SQLServer.
I am trying to figure out an alternative and test if something like this could make a difference.. I know the code i sent you is crapy, but this is just a test to see what will work better. I know I have lot to do.
I was wondering if i can batch up all my inserts/updated and deletes into an Array an execute them in bulk. If possible I am sure that should work much faster than batch executes using JDBC.. You help will be appricated..
Thanks
May 13, 2003 - 6:19 pm UTC
the batch executes in jdbc would be just as fast.
do you have a tkprof of the optimal solution in java?
ARRAY PROCESSING
Nirmal, May 13, 2003 - 7:36 pm UTC
Hi Tom,
Sure I can get you the tkprof. I am at home right now. I will send you tomorrow as soon as I get to the office.
Thanks
"SQL injection"
Tony, May 14, 2003 - 3:20 am UTC
Is SQL injection bug for SQL server alone or its applicable for Oracle db also?
May 14, 2003 - 7:10 am UTC
Oracle, Informix, you name it.
consider the jsp that asks you for username and password. It'll execute a query like:
"select count(*) from my_user_table where username = '" + UserName +
"' and password = '" + PassWord + "'"
if count > 0 then -- you are IN...
using concatenation instead of binds. great, I'll give you a username/password of
username = BOB
password = a' or 'a'='a
well, your query turns into
select count(*) from my_user_table where username = 'BOB'
and password = 'a' or 'a'='a'
hmm. I can change result sets, inject arbitrary SQL into your SQL. Not good.
Binds -- they are not just for performance....
ARRAY PROCESSING
Nirmal, May 14, 2003 - 1:03 pm UTC
Hi Tom,
Continueing on our discussion, I realized that SQLServer has primary keys as clustered on 99% of the tables. Do you think it would be a good idea to have all my pk's under cluster(Though I am not convenced that it's a good idea)..
This Apps is having a heavy inserts and deletes..
thanks
SQL injection applicable for procedures?
Tony, May 15, 2003 - 2:52 am UTC
we use packages or procedures and put all the quries in it.
The middle tier just calls those procedures alone by passing parameters. In this case, do I still have to worry about SQL injection bug?
May 15, 2003 - 9:27 am UTC
do you do dynamic sql in your plsql?
if so, sure, if you do not use bind variables - your plsql is subject to it.
do they NOT use bind variables?
if so, if they concatenate strings, you are very (even in a worse way) prone to it.
Consider the routine in java or vb:
sqlStmt := "begin p( '" + some_inputs + "' ); end;"
looks blindingly simple, cannot go wrong, or can it.
I give you some inputs:
abc' ); delete from t; dbms_output.put_line( '
suppose ABC is valid, p will be happy with that. Now what block gets executed:
begin p( 'abc' ); delete from t; dbms_output.put_line( '' ); end;
now, replace delete from t with pretty much anything you want, execute immediate 'drop table important_table'; -- think about what might go there and you would just execute.
any application that accepts inputs from users and does not use bind variables to get that to the database -- any database -- is 100% prone to sql injection security bugs
Is it that much easy to change SQLs?
Tony, May 16, 2003 - 2:03 am UTC
First of all, How is it possible to change SQLs in any application?. I have read some sites but still not clear. If you give an explanation, even novice can easily understand.
May 16, 2003 - 9:58 am UTC
huh?
this question needs an explanation.
ARRAY PROCESSING
Nirmal, May 16, 2003 - 11:52 am UTC
Hope you will appricate this one. But I am still looking for a neater stuff were i do not have to create those many arrays to get the values from my java program, which sends array of values to this proc.
Any suggestion will be appricated:
create or replace type CS1_NUM_ARRAY as table of number;
create or replace type CS2_DATE_ARRAY as table of date;
create or replace type CS3_NUM_ARRAY as table of Number;
create or replace type CS4_NUM_ARRAY as table of Number;
create or replace type SS1_NUM_ARRAY as table of Number;
create or replace type SS2_DATE_ARRAY as table of date;
create or replace type SS3_NUM_ARRAY as table of Number;
create or replace type SS4_NUM_ARRAY as table of Number;
create or replace type SS5_NUM_ARRAY as table of Number;
create or replace type SS6_NUM_ARRAY as table of Number;
create or replace type SS7_NUM_ARRAY as table of Number;
create or replace type SS8_NUM_ARRAY as table of Number;
CREATE OR REPLACE procedure p_get_array
(v_table varchar2, v_cs1 CS1_NUM_ARRAY,v_cs2 CS2_DATE_ARRAY,v_cs3 CS3_NUM_ARRAY,v_cs4 CS4_NUM_ARRAY,
v_ss1 SS1_NUM_ARRAY,v_ss2 SS2_DATE_ARRAY,v_ss3 SS3_NUM_ARRAY,v_ss4 SS4_NUM_ARRAY,
v_ss5 SS5_NUM_ARRAY,v_ss6 SS6_NUM_ARRAY,v_ss7 SS7_NUM_ARRAY,v_ss8 SS8_NUM_ARRAY)
AS
v1_table varchar2(50) := 'tbl_'||v_table;
l_start_time date;
l_end_time date;
l_difference number;
counter number := 0;
ins_ctr number := 0;
array_size number := 50;
-- declare array types ...
-- -------------------
type number_table is table of number index by binary_integer;
type date_table is table of date index by binary_integer;
-- define arrays ...
-- -------------
my_cs1_array number_table;
my_cs2_array date_table;
my_cs3_array number_table;
my_cs4_array number_table;
my_ss1_array number_table;
my_ss2_array date_table;
my_ss3_array number_table;
my_ss4_array number_table;
my_ss5_array number_table;
my_ss6_array number_table;
my_ss7_array number_table;
my_ss8_array number_table;
begin
-- Now read the data and insert it into the table ...
-- ---------------------------------------------
begin
for k in 1..v_cs1.COUNT loop
ins_ctr := ins_ctr + 1;
my_cs1_array(ins_ctr) := v_cs1(ins_ctr);
my_cs2_array(ins_ctr) := v_cs2(ins_ctr);
my_cs3_array(ins_ctr) := v_cs3(ins_ctr);
my_cs4_array(ins_ctr) := v_cs4(ins_ctr);
my_ss1_array(ins_ctr) := v_ss1(ins_ctr);
my_ss2_array(ins_ctr) := v_ss2(ins_ctr);
my_ss3_array(ins_ctr) := v_ss3(ins_ctr);
my_ss4_array(ins_ctr) := v_ss4(ins_ctr);
my_ss5_array(ins_ctr) := v_ss5(ins_ctr);
my_ss6_array(ins_ctr) := v_ss6(ins_ctr);
my_ss7_array(ins_ctr) := v_ss7(ins_ctr);
my_ss8_array(ins_ctr) := v_ss8(ins_ctr);
-- If the array is full, insert it into the database ...
---------------------------------------------------
if ( ins_ctr = array_size ) then
execute immediate
'begin
forall j in 1..:N
insert into :T1
values(my_cs1_array(j),my_cs2_array(j),my_cs3_array(j),my_cs4_array(j));
end;'
USING rtrim(v1_table),array_size;
execute immediate
'begin
forall j in 1..:N
insert into tbl_TSAggBuffer
values(
my_ss1_array(j),my_ss2_array(j),my_ss3_array(j),
my_ss4_array(j),my_ss5_array(j),my_ss6_array(j),
my_ss7_array(j),my_ss8_array(j));
end;'
USING array_size;
ins_ctr := 0;
end if;
end loop;
exception
when others then
DBMS_OUTPUT.PUT_LINE(substr(sqlerrm,1,100));
end;
-- Now insert the last batch, commit and close the file ...
-- ----------------------------------------------------
if ( ins_ctr > 0 ) then
execute immediate
'begin
forall j in 1..:N
insert into :T1
values
(my_cs1_array(j),my_cs2_array(j),
my_cs3_array(j),my_cs4_array(j));
end;'
USING rtrim(v1_table),ins_ctr;
execute immediate
'begin
forall j in 1..:N
insert into tbl_TSAggBuffer values
(my_ss1_array(j),my_ss2_array(j),
my_ss3_array(j),my_ss4_array(j),
my_ss5_array(j),my_ss6_array(j),
my_ss7_array(j),my_ss8_array(j));
end;'
USING ins_ctr;
end if;
commit;
end;
/
May 16, 2003 - 5:09 pm UTC
seem to me you only need two types here?
numArray
dateArray
add a third for completeness
vcArray
and you would have them all. I don't know why you feel compelled to make all of those types?
"SQL Injection"...
Robert, May 16, 2003 - 12:01 pm UTC
Tom, this "SQL Injection" is a "new" thing ?
'cause I don't think you mentioned a word of it in
"Expert 1 to 1"
May 16, 2003 - 5:10 pm UTC
Its been around for as long as people have been gluing in strings. I added it to the "bind variable repitoire" solely because people said "well, I don't need to do this in sqlserver, blah blah blah (they have no shared pool)"
So, I gave them yet another good reason that they need to do it (ESPECIALLY in sqlserver -- it is frightening what sql injection can do in their database!)
ARRAY PROCESSING
Nirmal, May 20, 2003 - 4:40 pm UTC
You Said.
seem to me you only need two types here?
numArray
dateArray
add a third for completeness
vcArray
and you would have them all. I don't know why you feel compelled to make all of those types?
I Said:
I will appricate if you could give a small example..
Thanks
May 21, 2003 - 7:24 am UTC
example of what?
SQL Injection (again)
Martin, May 21, 2003 - 8:35 am UTC
Hi Tom,
I couldn't come up with a test case where I can execute arbitrary SQL statements if using EXECUTE IMMEDIATE for dynamic SQL, since EXECUTE IMMEDIATE will fail with an "invalid character" error (well, it does at 9.2.0.3 anyway), i.e.
SQL> ed
Wrote file afiedt.buf
1 begin
2 execute immediate 'select a from t where a = 10; delete from t';
3* end;
SQL> /
begin
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 2
Does this mean that the procedure is "safe" (in inverted commas, of course we should be using bind variables etc.) if using this method. If not, can you give a quick example, where systems using this method can be "got at".
Thanks in advance
May 21, 2003 - 9:38 am UTC
if you are executing SQL in ORACLE, sql injection is limited to:
a) me changing the meaning of your query (the username/password example). This will give me access to stuff I otherwise would not have access to.
b) calling functions that take IN parameters and are callable from SQL. So, I might be able to run some of your code you did not intend me to run.
At the end of the day, it doesn't matter -- it is an 100% verifiable security hole and a performance sink.
In SQLServer - the security hole is (surprise) even bigger -- in sqlserver that statement you built would fly, it would execute.
ARRAY PROCESSING
Nirmal, May 21, 2003 - 4:38 pm UTC
YOUR FOLLOW-UP:
seem to me you only need two types here?
numArray
dateArray
add a third for completeness
vcArray
and you would have them all. I don't know why you feel compelled to make all of
those types?
I SAID:
Forget about the example, could you elaborate you comments above??
May 21, 2003 - 5:10 pm UTC
you declared a type per variable.
I would declare three types and use them over and over and over.
...
create or replace type CS1_NUM_ARRAY as table of number;
create or replace type CS2_DATE_ARRAY as table of date;
create or replace type CS3_NUM_ARRAY as table of Number;
create or replace type CS4_NUM_ARRAY as table of Number;
create or replace type SS1_NUM_ARRAY as table of Number;
create or replace type SS2_DATE_ARRAY as table of date;...
why would you do that.
ARRAY PROCESSING
Nirmal, May 22, 2003 - 11:23 am UTC
OK The reason for me to do that is that I have to pass an Array of values for each of the columns from my java program and catch it all at once in my stored procedure. This is how my Java looks like(Not the real program):
String intArray[] = new String[intList.size()];
Iterator iints = intList.iterator();
int i=0;
while (iints.hasNext())
{
intArray[i] = (String) iints.next();
System.out.println(intArray[i]);
i++;
}
System.out.println("Value of i :" + i);
ArrayDescriptor descriptorint = ArrayDescriptor.createDescriptor( "INTARRAY", conn );
ARRAY int_array_to_pass = new ARRAY( descriptorint, conn, intArray );
//Process Dates
String dateArray[] = new String[dateList.size()];
Iterator idates = dateList.iterator();
int j=0;
while (idates.hasNext())
{
dateArray[j] = (String) idates.next();
System.out.println(dateArray[j]);
j++;
}
ArrayDescriptor descriptordate = ArrayDescriptor.createDescriptor( "DATEARRAY", conn );
ARRAY date_array_to_pass = new ARRAY( descriptordate, conn, dateArray );
//OraclePreparedStatement ps =
// (OraclePreparedStatement)conn.prepareStatement
// ( "begin give_me_an_array(:x); end;" );
oracle.jdbc.OracleCallableStatement ps =
(oracle.jdbc.OracleCallableStatement) conn.prepareCall ("begin give_me_an_array_test(:x,:y); end;");
ps.setARRAY( 1, int_array_to_pass );
ps.setARRAY( 2, date_array_to_pass );
ps.execute();
May 23, 2003 - 8:19 am UTC
so, you only need 3 array types -- no one per input value.
how can i do this
umesh, May 23, 2003 - 2:23 am UTC
I have a table called user_tab which has a column user_id
in one of our application 2 users have entered a user_id as
1) abcd'"
2) abcd"'
when i click on a jsp page i have to check wether this user exists
how do i write a query for the same
i tried
"select * from user_tab where user_id ='" + <user_id> + '"'
but in vain
can it be done ?
thanks
May 23, 2003 - 8:46 am UTC
YOU USE BIND VARIABLES -- YOU NEVER GLUE IN STUFF LIKE THAT.
your query would be
"select * from user_tab where user_id = ?"
period, end of problem.
Do this for me -- search google for:
"sql injection"
and tell me what happens when an end user inputs
abcd' or 'a' = 'a
into your "enter a username field". Hmmmmmmm -- that won't happen with binds (and you'll achieve slightly more scalability).
seek out and destroy ALL JAVA CODE that doesn't use bind variables on your system. If not for the performance, for security.
ARRAY PROCESSING
Nirmal, May 23, 2003 - 9:38 am UTC
Hi Tom(or whoever)
THANKS A LOT..
array processing
kti, July 23, 2003 - 12:51 pm UTC
hi tom,
I know its an array procesing topic so please try and see how i can do the following
I have a table with 6 columns a1 a2 .. a6
I need to scan this table where if any of the columns contains 'VIT' I need replace with the next col
eg
if a1 = 'VIT'
then
a1 = a2,
a2 = a3
a3 = a4
a4 = a5
a5 = a6
a6 = null
else
if a2= 'VIT'
then
a2 = a3
a3 = a4
a4 = a5
a5 = a6
a6 = null
else
and so on until non of the columns a1 .. a6 = 'VIT'
July 23, 2003 - 7:11 pm UTC
ouch, hurts my head to think about it.
guess I would concatenate all of the columns together (say the columns are varchar2(10)) and substr them back out:
ops$tkyte@ORA920LAP> select * from t;
C1 C2 C3 C4 C5 C6
---------- ---------- ---------- ---------- ---------- ----------
VIT a b c d e
a VIT b VIT d e
a VIT b VIT VIT e
VIT VIT b VIT VIT e
ops$tkyte@ORA920LAP> update (select t.*,
2 substr( data, 1, 10 ) new_c1,
3 substr( data, 11, 10 ) new_c2,
4 substr( data, 21, 10 ) new_c3,
5 substr( data, 31, 10 ) new_c4,
6 substr( data, 41, 10 ) new_c5,
7 substr( data, 51, 10 ) new_c6
8 from (select t.*,
9 rpad( decode(c1,'VIT',null,c1), 10 ) ||
10 rpad( decode(c2,'VIT',null,c2), 10 ) ||
11 rpad( decode(c3,'VIT',null,c3), 10 ) ||
12 rpad( decode(c4,'VIT',null,c4), 10 ) ||
13 rpad( decode(c5,'VIT',null,c5), 10 ) ||
14 rpad( decode(c6,'VIT',null,c6), 10 ) data
15 from t
16 where c1 = 'VIT' or c2 = 'VIT' or c3 = 'VIT'
17 or c4 = 'VIT' or c5 = 'VIT' or c6 = 'VIT' ) t
18 )
19 set c1 = new_c1, c2 = new_c2, c3 = new_c3, c4 = new_c4, c5 = new_c5, c6 = new_c6
20 /
4 rows updated.
ops$tkyte@ORA920LAP>
ops$tkyte@ORA920LAP> select * from t;
C1 C2 C3 C4 C5 C6
---------- ---------- ---------- ---------- ---------- ----------
a b c d e
a b d e
a b e
b e
ops$tkyte@ORA920LAP>
array processing
kit, July 23, 2003 - 5:33 pm UTC
Hi tom,
why am i seeing my questions answered status when they are not
am i submitting them incorrectly
July 23, 2003 - 9:28 pm UTC
erh?
don't understand what you are saying.
array processing
kit, July 24, 2003 - 6:38 am UTC
sorry for the earlier comment. I thought my comments were not being read. I had a hasj join issue that still needs looking at. Hope you can find more people like on your team that can anwer questions as you're the best
how did you think of that solution. I was going to use collections and loop though the array but single update
fantastic
July 24, 2003 - 8:45 am UTC
(and i told you 'hash question is bigger then a breadbox, when I'm taking questions we can deal with it there')
sour grapes
CW, January 19, 2004 - 7:11 am UTC
Rather than dis the competition why can't you concentrate on making a DB that does stuff right 'out of the box'.
It's 1970s technology - ADA, jeezuz ! , it requires a degree in "Oracle" to make it perform well, it co$t$ and is still designed so that you inevitably need Oracle con$ultan$ to get it to do what you want.
If it were a car it would be a Formula one racer from the 1970s. You need a mechanic to constantly tune the carbs and wipe it with an oily rag to get it to work right.
SQL Server ain't perfect, but to imply Oracle is vastly superior is, at best, misleading and is sour grapes. It's a shame Oracle employees devote too much time to MSft bashing and not enough time fixing their DB.
January 19, 2004 - 9:52 am UTC
huh????
where are you coming from?
<quote>
Tell you what -- code it right for Oracle, code it right for SQLServer and then
run 10, 100 conncurrent sessions (you know, like the "real world") and see what
happens. See which one scales. See which one flies then.
</quote>
where is that a "dis" -- thats a challenge.
dude, you are just so so sooooo far off base, you don't even know. you don't even know that using binds would make for better sqlserver applications. sigh.
lead horse to water
can you make them drink.
sometimes yes.
sometimes no.
you like what you know.
you know what you like.
wish i had a time machine so i could transport you back to your early days with sqlserver -- so you could remember how confusing that particular product was the first time you saw it as well.
sigh.
sqlserver is written in C. C is an old language. does that make it archiac? Have you even looked at transact sql? wanna talk archiac?
I know lots of people who do Oracle just dandy without advance degrees or consulting. Perhaps they
like what they know.
know what they like.
and they would find sqlserver excessively "hard" as well.
A reader, January 19, 2004 - 10:40 am UTC
This is for CW from London.
SQL Server guys talk big really big but when you try to confront them with Oracle guys or guys who have worked on different databases they dont even wana talk/reply.
Recently I was going through "Inside SQL SERVER 2000" by Kalen Delancy on page 106 she emphasizes (Windows/SQL SERVER) performance and integration of sql server with THE OS, i pointed her to Toms link about ubiquity (for her opinion) which i agreee with Tom as to what will happen to MS guys if the OS changes, its been more than a week she hasn't replied.
CW Don't get people started on that SQL SERVER CRAP!!!
Thanks
Rahul.
so, is it a Yes or No?
Gabriel, January 19, 2004 - 3:36 pm UTC
<quote>sqlserver is written in C. C is an old language. does that make it archiac?</quote>
I truly admire your ability to be un-ambiguous with your answers in 99% of the cases ... but with this one ...
“C is an old language” … Ok I can take this since it is a statement of fact.
But Â… archaic because of being written in C?
If ‘No’ ==> guess wasn’t much point to it ... or my English fails me again!
If 'Yes' ==>
IsnÂ’t the Oracle server written in C (and some C++ sure)? Â… (and IÂ’m not asking about the Java GUI stuff for OEM, etc.)?
What happened to the “Java is just a language” … presumably the same goes for C, C++, PL/SQL, etc.)?
In my view some applications are archaic before they even go production Â… Transact SQL wouldÂ’ve been archaic by the time they finished defining the lexical analyzer and the parser Â… what does C have to do with anything (at least in the context of multi-platform server development)?
For the record Â… IÂ’ve never done anything worth mentioning in SQL Server and I cannot look for more than 2 seconds at Transact SQL.
Thx
January 19, 2004 - 3:59 pm UTC
I was making a reference to their dig on Ada (which by the way was/is a really cool language. had tons of really nice features)
I was making the point that the age of the language, in reference to what I thought was a really silly comment:
It's 1970s technology - ADA, jeezuz !
has nothing to do with nothing. Compare something on it's merits, not age. Age has nothing to do with anything here.
I'm from the 70's -- geez, actually i predate the 70's -- geez, does that make me "old technology". I sure hope not.
Let them compare PL/SQL (which is Ada like - pascal like - modula like - pl/1 like) to T-SQL -- the barest of scripting languages ever (well, since the DOS batch/cmd scripting language that is)...
The age of something has nothing to do with anything.
knew it was a slip ... couldn't resist though
Gabriel, January 20, 2004 - 2:18 am UTC
<quote>I'm from the 70's -- geez, actually i predate the 70's -- geez, does that make me "old technology". I sure hope not.</quote>
Actually, it does Â… but youÂ’ve proven in many occasions well in tune with the "current technologies" Â… so, here you have it, I see the exposure to "older" stuff as a huge advantage really.
Ada Â… wish I had the chance to use it (the US/UK military contractors were not really hiring programmers on my side of the world at the time) Â… I read on it after starting with PL/SQL and saw immediately where the PL/SQL syntax came from Â… well, that was a good choice indeed Â… and fortunate I would say Â… Oracle without PL/SQL (or with something poor like T-SQL) wouldÂ’ve been just another RDBMS.
As for the "sour grapes" chap from London, I would be curious to know what exactly, he thinks, needs "fixing" with the Oracle DB to bring it on par (!?!?!?!?) with SQL Server. The guy came swinging out of nowhere Â… Problem with a patch or something? Â… Hired the wrong consultant? Â… Oracle doesnÂ’t do the programming for him?
Case in point: Nirmal back in May 2003 went away disappointed that Tom didnÂ’t, I guess, "appreciate" his PL/SQL code Â… well, there were so many things wrong with it that there wasnÂ’t much short of _hurting_ his pride:
a. the procedure listed would not even compile
b. buggy error handling (since it potentially hides the errors)
c. no asserting what-so-ever on the input parameters (those arrays better be the same size)
d. one dynamic sql trying to bind the name of a table Â… and the bind variables positionaly incorrect
e. the other dynamic sql unnecessarily dynamic
Ok Â… maybe heÂ’s new to PL/SQL and Oracle and this is just some hastily put together code Â… but Â…
f. the logic? Â… load arrays in Java, pass them to Oracle and Â… copy them to local arrays in batches of 50 and bulk load them Â… why break the data into smaller chunks? Â… how would this make it faster?
Was he the wrong person for Â… <quote>I am in the process of migrating from SQLServer to Oracle and the condition is if Oracle runs faster than SQLServer</quote>? Surely, with him, that Java application is still on SQL Server (I cannot believe I used "SQL Server" and "Java" in the same sentence!) and another believer that Oracle doesnÂ’t do <quote>stuff right 'out of the box'</quote> was born.
You've missed the point
CW, January 21, 2004 - 5:47 am UTC
...and so the flame war begins.......
Let's calm down, see the world from both sides and try to understand why people might get frustrated with Oracle. Isn't that reasonable ?
and I never said I was a SQL server guy. I'm an app developer so databases are a means to an end, but I'm coming from Sybase and so, yes, Oracle is new.
So:
1. Why do Oracle require me to register to get any tech info from their website ?
...I'll take a shot in the dark here...perhaps it's so that their mktg dept can get hold of my personal details ;-) nice.
2. If Oracle > SQL Server( or Sybase) AND PL/SQL > TSQL then...WHERE is the Oracle for SQL Server programmers documentation? (and not the cr*p that's published in the Oracle migration workbench docs - that's a joke)
3. Temp tables, where d'ya get that idea from ?
4. Stored Procs that return a resultset. In TSQL this is easy, in Oracle this seems to require a cursor and a Package - which is like a struct ? Anyway, I'm having to do alot more work to do something which is trivial in Sybase - now, it may be that there is some logical explanation for this approach in Oracle, but I haven't found one (in the still useless migration documentation).
5. Clustered index -> index organised ? If I create a PK on Sybase it defaults to clustered & stores the data sorted by the PK. In Oracle I don't think it does this, you have to specify index organised ? Either way is fine, but *personally* I think it's more logical the Sybase way i.e the default behaviour is index organised. Again - a decent document would have saved me alot of pain here and, as yet, I still can't get the index organised syntax right !
6. Program too long error. Yoinks, more than 64k or is it 32k is that DIANA nodes or memory ? I think I last had 32k in my BBC micro and 64k in a Commodore 64 - that would have been about 1985. The phrase "sooo far off base" springs to mind ;-) Have I lost the plot here ? Maybe my Sybase-esqe use of Oracle is "sooo far off base" that I've made a huge coding mistake.....or maybe this limit is from 1985 :P
7. It's all about the developers - I'm not a horse. Your job isn't to punch me (& others) in the face until we agree that Oracle is best. Horses are really quite dumb animals, programmers.....well ;-). Databases are generally back-ends to somebody's front end. The worlds most popular front end is....Msft Windows...like it or not. So, if you want to beat Msft you must play by their rules and Msft invest time & money in application developers. They put effort into trying to make programmers lives easier.
Programmers are generally *NOT* database experts BUT programmers do write DB code SO progammers writing bad DB code will get poor performance SO they blame the back end ;-)
Show me the water, explain to me why it's good to drink and then show me where the tap is, I don't wanna drink from a hole in the ground ;-) Always, always, always aim to make life easier for the app developer. Geek DBAs may get off on all sorts of quirky syntax. An app developer will get bored,give up and do something hideous to the database.
8. Binds - I think I've got the message on that one. Binds are good....maybe, or are they? Yeah, they are :P
9. Back in the "Real World" I've very rarely (actually I don't think ever) seen Msft people slate the competition. They will quote benchmarks, or (Msft funded ;-) research but they don't make unqualifed remarks about other peoples stuff. You shouldn't either, if you really are better than them - it's sour grapes, it's unprofessional. You should justify and qualify why Oracle is gonna scale when SQL Server won't by FACTS (add links to Oracle funded research if you like ;-)
10 Commit OR commit suicide. Gotcha sucker ! Oracle doesn't auto commit (there is some server param I think) anyway , I won't say how much time was spent looking for my data, but on reflection it was a comedy moment. Again some DOCUMENTATION would have helped.
So Tom & others,
Apologies for my rant, but I think if you could see the Oracle world through my eyes you'd be annoyed ? frustrated ? p*s*ed off ? Fundamentally I know it's a good product, but it is hard to use it *the right way* when you have little experience. Make it easier for people migrating from other platforms, invest in documentation / web pages. Produce a "100 most common SQLServer migration mistakes" type of thing AND try to make the product easier & more intuitive to use.
If anyone has links to good docs / web sites then please let me know.
January 21, 2004 - 7:38 am UTC
1) shots in the dark, hmm, susposition, paranoia on your part is what I supose. Perhaps they just want to know who you are and keep track of what people use -- how they use it -- tie it all together. You know, like *lots* of sites do (i've accounts on MS sites -- can you spell "passport"? I've accounts on IBM sites -- to get at their documentation. I've accounts on Oracle sites as well -- and you know what -- they don't actually spam you)
so bzzzt. wrong answer.
2)
If Oracle > SQL Server( or Sybase) AND PL/SQL > TSQL then...WHERE is the
Oracle for SQL Server programmers documentation? (and not the cr*p that's
published in the Oracle migration workbench docs - that's a joke)
I don't know, why would you expect such a thing? there should be a "Language X for programmers of Language Y" book for every language?
tell me, whats the title of the "transact sql for plsql programmers" book?
Have you read the PL/SQL documentation?
Have you realized that perhaps there is not much mapping between the scripting language that is T-SQL and the language that is PL/SQL?
that perhaps you need to learn to program in PL/SQL -- not how to emulate sqlserver in Oracle (that -- that is where things fail. But to be fair, the opposite is true as well -- if you try to get SS to run an Oracle program -- well, good luck, they cannot -- way way too many differences in the concurrency and locking model. What works in Oracle failes in SQLServer and vice versa)
Have you bought any of the hundreds of PL/SQL books out there? (there are ALOT)
3) good question -- no wait, bad question.
Tell me -- where'dya get the idea that temp tables are a "good idea" in the first place? (sqlserver makes you use them at the drop of a hat. In SS it is "a good idea". In Oracle they are "not necessary, not used". We got along fine without them for many years before SS was even a database).
I've written lots of Oracle code.
I've used a temp table once (as an interface table).
I've taken dozens of multi-page SS stored procedures (wholly unreadable mess of procedural logic) and turned it into a single SQL statement which it should have been from the get go.
Here is an Oracle temp table done right:
select * from
( YOUR_QUERY you would have put into temp table 1) a,
( your_query you would have put into temp table 2) b,
.....
where
temp tables are a crutch needed by sqlserver -- temp tables are a tool you can use in Oracle if and when needed -- you just define them as part of the application itself.
Guess what -- this is in fact "Oracle", not "Sqlserver". If we did things just as they did -- what would be the point? And why pray tell should the rest of the world "do it just like MS"? You do understand that MS is the latest entry to the rdbms market right?
4) Ok,
create or replace function foo return sys_refcursor
as
l_cursor is sys_refcursor;
begin
open l_cursor for select * from emp;
return l_cursor;
end;
hmmm, you're right, its really hard??? or not? I don't know, as a coder, I sort of like having formal named parameters for outputs or a clearly defined return value from a function.
Tell me, in sqlserver:
exec foo
does that return
a) 0 result sets
b) 1 result set
c) N result sets
and if b or c is true (but you cannot tell without reading the code), what do those result sets mean? what order are they in?
Now, Oracle
create procedure foo( p_input in empno, p_emp_result_set out sys_refcursor )
Well, I can sort of see the inputs and outputs and it is a bit "self documenting"
In the client -- what extra code do you write? (i write no extra code, if you are -- it is self inflicted).
In the server what extra code? well, a declare -- that's it.
(in 8i, and before you must define once in your database a package like this:
create package types as type rc is ref cursor; end;
and then use the datatype types.rc instead of sys_refcursor)
again, I'll say this -- this is Oracle, it is different than SS. SS is different than Oracle. I've never understood this ref cursor/result set thingy here cause I've never had anyone show me line by line "what is so hard" about this -- never (there a challenge -- show me the SS code and show me the Oracle code and show me why the Oracle code is hard/obscure/ungainly/large)5) Sybase does not default to a clustered index.
But anyway "why does a feeling" mean anything. do you have the numbers, the benchmarks, any facts that the overhead of their clustered index (which actually makes inserting slower in their database BUT spreads the inserts out so their extremely poor locking and concurrency model appears to sort of work in some cases......) is a "good thing"
no - it does not exist (in the positive sense). SS uses clustered indexes in an attempt to spread inserts out all over a table because of extreme contention they would otherwise experience.
So.... do you have bitmap indexes? hash clusters? IOTs (without the 110% overhead of emulating that in SS????)? b*tree clusters? partitioning? parallel operations? (list goes on and on and on and on and the answers are "no")
6) you provide no example, but the only time I see this is when you have code that goes on for pages and pages and pages with lots of if then else if yadda yadda yadda (calls out for subroutines). It is the parse tree -- not the size in bytes of the source code.
It all does really (truly) come back to "good code". you are using procedures -- not packages (why -- because, well, tsql does not have this functionality, its not a programming language, its a scripting language but I digress).
You have a single, monolithic, huge, page after page of code procedure.
It follows none of the "best practices" developers have been taught since the dawn of computers (modularize your code, use the language to help you develop modular, maintainable code)
tell you what -- how about you post the code that didn't compile, and let people comment on whether it falls into "a good idea" or "really bad practice, regardless of the language"? I post code all of the time, no one will mind more code....
7) It is not all about the developers, you have taken a far too ethnocentric view of YOUR world
I've said it before and I'll say it again. its all about the DATA. Your applications, they will be born, live and die many times before the data goes away. the data we work with today was in the most part first developed in the 60's. The data far outlives the applications.
So, if your applications screw up the data -- we've got a problem.
If you don't understand concurrency control, we've got a problem.
Tell me -- why do developers thing "tis OK to get magazines on my favorite language, get training on it, go to developer days to learn neat gui things, learn interesting algorithms" but -- even though their job is to develop DATA BASED applications -- they ignore the very tool they are using???? I'll bet you've had training in programming -- so, tell me database programmer -- how many hours of training in relational databases have you logged?
Don't get me wrong, I'm a developer -- I started as a developer. PL/1 (archiac language from mainframes, mainframes coming from the 1960's means they must not be used anymore). Using SQL/DS, DB2, then ingress, gupta, dbase even. Then informix, sybase, oracle, sqlserver. One thing I learned was a successful DATA BASED application depends on someone (gasp) understanding a database (i'm embarrassed by some of the bone headed mistakes and massive misunderstandings I had when first learning this stuff). I also learned that -- hey, these products are different.
Windows is an operating system
Unix is an operating system
VM/CMS is an operating system
guess what -- they are different. (they are all "posix" though, hmm, but if I try to code on unix what I code on windows or vice versa -- guess what happens??)
I can recommend a book -- you probably are not interested at this point, but I'll offer it up. It is called "expert one on one Oracle" -- accessible from my home page. I try to show you the water, and how and why to drink it. (i even cover many of the above topics believe it or not, even the clustered index thingy) anyway....
8) yes they are -- even in SS believe it or not.
9) you are kidding right? you've never had them do an anti-oracle presentation? man, you are missing a great thing (i've got the slides, it is funny -- i love to be in the room at the same time with them, just to help clear up some points of their confusion). give me a break.
and -- who is "slateing" them here. I'm saying "HEY- we are not sqlserver, they are not oracle -- we are different. do not expect to take code that works in SS and run it on oracle unchanged (and vice versa). Not more then you would expect to take windows code and run it on unix and vice versa. it just don't fly"
Wait -- i don't have to diss SS, they do it themselves:
</code>
http://www.sql-server-performance.com/lock_contention_tamed_article.asp <code>
<quote>
Granted, if you've only got a few occasional users, you won't have much trouble with SQL Server's out-of-the-box behavior. You'll be hard pressed to see these problems with simple in-the-office tests or deployments involving just a few users.
But throw a couple hundred concurrent users at your database and a constant stream of INSERTS and UPDATES with quite a few DELETEs sprinkled in, and you'll start reading Oracle literature and eyeing your war chest. However, I've got a solution for you that will only cost you a code review, a few minor tweaks, and a system test. You do have a system test procedure in place, right?
</quote>
and i love the "solutions" proposed in the following paragraphs (makes interesting reading).
solution 1 includes this caveat:
...
For financial code and denormalized aggregates (those little counters of related data that you stash away and try desperately to keep accurate),
you should play it safe and not use this technique. .....
solution 2 includes this:
....
However, be aware that if you are wrong and lots of rows are affected, either the database will take the initiative and escalate to page locks, or you'll have a whole army of row locks filling your server's memory and bogging down processing
.......
and closes up with this:
<quote>
Disclaimer
Use these techniques with caution and discretion. The way I approached it was to look at all my stored procedures and ad hoc queries, and based on my understanding of where and how they were used, I decided whether it would be acceptable for the caller or user to get possibly incorrect results for NOLOCK, and whether it was likely that more than a few dozen rows would be locked with ROWLOCK. In almost all cases it was fine, but maybe for your code you should be more careful.
You might need to produce separate procedures based on whether or to lock, and how to lock. There are other incantations (PAGLOCK, TABLOCK) which you might want to use when you know the UPDATE or DELETE query will affect many rows.
</quote>
so tell me how a PROGRAMMER who doesn't understand the database is going to figure out this stuff?????? Remember -- this is from the "easy to use guys" right -- but wait, is it really or have you been lulled into a sense of "this is easy". Under the covers I'll betcha you there are nasty old bugs you are not even aware of in your data (i see it time after time after time -- not just in SS but in Oracle and every database - -why? cause the programming professionals did not bother to understand or learn the tool they are using)
The facts are in reality (i love it when people invoke "real world", as if we live in a fantasy planet somewhere where all is good and lovely. hmmmm).
Anyway, if you want to read it about it -- i wrote about it. people write about it. Heck, even the sqlserver pros write about it -- how to get around their concurrency model.
Here -- one more challenge. SHOW ME WHERE on this page I've "dissed" sqlserver?????
<quote>
Tell you what -- code it right for Oracle, code it right for SQLServer and then
run 10, 100 conncurrent sessions (you know, like the "real world") and see what
happens. See which one scales. See which one flies then.
</quote>
does that "diss them" or does it point out "real world reality" that
a) code it for sqlserver and run it on oracle isn't going to work (not anymore then code it for oracle and run it on sqlserver)
b) see which one scales -- please, benchmark it, test it -- the proof is in the pudding. SEE which one flies.
10) NOW, now I'm LOL, actually ROTFL
I'll play dictionary here:
auto commit: mode used by databases that have severe contention and locking issues. makes it impossible to perform transactional processing, leading to data integrity issues and corrupt data. DBA's have a love hate fear of this mode. They love it because it doesn't lock up their database. They fear it because they know it will lead to data integrity issues. It is not a feature, it is a failing.
Documentation? Have you
a) taken ANY training on relational databases (the tool you are using)
b) read the concepts guide (which does actually cover this stuff)
c) asked anyone with experience for help
The migration from SS to Oracle doc would be very short, here it is:
"forget everything you've 'learned'. These are different beasts, with different design spec's and different goals in mind. You need to read the concepts guide, the application developers guide and learn the tool you have at your disposal. It is not something you will learn and master in a day, or even a week. But the same is true of SS -- just as you probably learned something new each day with that tool -- you will with Oracle."
So, did SS make that investment for the other way? do you have the 100 most common PLSQL migration mistakes? I'd love to see that myself
A reader, January 21, 2004 - 11:11 am UTC
Tom,
I think the major problem with MS users is they are so used to click click, the moment they have to DIY then they start complaining about the product and eventually loose interest.
Thanks.
oh dear
CW, January 21, 2004 - 11:48 am UTC
Tom,
I refer you to the title of my previous post. Please don't reply, I'm concerned that you might have a coronary.
It's before my time,but, during the Vietnam war I believe they said it was a battle of hearts & minds......have a think about that.
bye.
January 21, 2004 - 3:15 pm UTC
this is software, this is software design, this is stuff based on scientifically proven fact.
this is not dogma. this is not a war.
sorry -- i thought I asked good questions too. no redress, oh well.
re-look at your first post and see who is coming in with dogma, sourgrapes, et.al. feel free to follow up some of my questions if you like. Like -- other then the fact you had to *learn* about ref cursors -- much like you *had to learn* about how sqlserver did it at sometime -- Like how ref cursors are this onerous, terrible, hard to code, many times cumbersome feature? i'd really really be interested -- really.
or maybe why "autocommit" is "a good thing" (it is the worst thing one can imagine really -- read a bit about databases and transaction processing and you'll sort of know "why")
or just point out where I've "dissed" the competition? that's how this sort of started....
or give us the example code that blows up -- just to see what it might look like?
no coronary here. fit and healthy. no worries with that.
Vietnam was before my time as well -- but this isn't a philosophical thing here either.
Why Oracle, Why SS, Why Sybase
NAM, January 21, 2004 - 12:33 pm UTC
It interesting to watch you guys trying to see who's got the best relational database technology.
I generally prefer the Versant object database because
- its much easier to use,
- faster to develop applications with,
- it typically has performance at least 2 orders of magnitude (and often 3 or 4) above ANY relational database with very little effort.
- it doesn't need DBAs
- I don't need to worry about indexes,
- I can have strings of variable lengths (what a revolution!),
- I can have collections
- I can represent the data in a way that represents the real world and my application instead of turning it inside out. I don't need to worry about link tables (or join tables or what ever its called when you try and mundge a many-to-many relationship into a RD).
- I can have inheritance, polymorphism.
- I don't need a whole bunch of stored procedures that end up being a nightmare to maintain.
- I can have huge transactions, hundreds of simultaneous connections and I didn't need to configure a thing, it just comes like that.
At the end of the day I'm concerned with getting my applications to my users as quickly as possible, with as much functionality as possible and in a way that can be easily maintained through the life of the application. The database is just a means to an end and I'm sorry but relational database technology just doesn't do it for me, the sooner the technology is dumped the sooner we can get on with giving the users what they want.
January 21, 2004 - 3:21 pm UTC
hah hah, lol.
thanks for the might fine laugh.
tell me, can you build something like say "a banking system" on that? or maybe a data warehouse to mine all of the stuff wal mart sold last week? (i can see it now, an object per sale, message all objects).
appropriate for somethings perhaps -- but in general? sorry. I don't agree.
client server was giving the users what they wanted. or at least what they thought they wanted. that -- well, we can see how "good" that idea was.
I see it all of the time "oh, well, we sort of modeled the objects from this perspective. sorry but your question cannot really be answered very efficiently (if at all) from our model. but that's ok, we'll just model it differently and duplicate the data over".
well, I guess time will tell at the end of the day.
A reader, January 21, 2004 - 1:07 pm UTC
NAM from UK so what are you doing here?? :-)))
Nam - where are the TPC benchmarks?
Jim, January 21, 2004 - 4:39 pm UTC
I find it difficult to believe there is any database out there that is 3 or 4 orders of magnitude faster than Oracle (or SS or Sybase or DB2, etc.). (Assuming that the code and use of the database are written effeciently.) 4 orders of magnitude is 10,000 times faster. Given the physics of the problem Nam is blowing smoke. (to put it politely)
If not, then where are the audited industry recognized benchmarks demonstrating such lightening speed? I know, it is a conspiracy led by Microsoft, IBM, Oracle, Sybase et al to supress such information. Yes, of course, that's it; Larry and Bill are in collusion. :-)
Came from INGRES
Gary, January 21, 2004 - 7:33 pm UTC
I moved to Oracle environment from Ingres many years ago.
You do get used to any environment you work with long enough.
I was surprised that Oracle (at that time) didn't support index-organised tables. Now, looking back, I remember that we had a monthly process that re-organised one large table from one index key to another, processed it, and re-organised it back (all for improved performance). And I thought there was nothing 'wrong' in that.
However, I still dislike SQL*Plus for ad-hoc type queries, and have fond memories of INGRES's ISQL.
PS. There probably would be a market for books for developers moving from Oracle to SQL-Server and vice-versa, but it would need to be printed on asbestos
January 21, 2004 - 7:54 pm UTC
i like the asbestos concept......
we did have b*tree clusters way back then -- they would (do) cluster data in a manner very similar to IOT's. Used quite extensively in the data dictionary to keep all of the data about a segment physically colocated together.
NAM, January 22, 2004 - 4:38 am UTC
“tell me, can you build something like say a banking system on that?”
:- Built one dude, last seen looking after £300Billion Sterling of interest rate swaps and futures and £1Billion Sterling cash.
“data warehouse”
:- go visit www.objectivity.com if you want to see a really big database!
“client server was giving the users what they wanted. or at least what they
thought they wanted. that -- well, we can see how "good" that idea was.”
:- User want loads of functionality, they want it all now and they want to change the system whenever they feel like it. Tell me, when did a system built on a relation database ever deliver ANY of these?
Tell me also, if you write your application in an OO language, how do you get data to and from a relational database (maybe you donÂ’t believe in OO programming either?). DonÂ’t tell me, let me guess, an object persistent layer? Joke!
“I find it difficult to believe there is any database out there that is 3 or 4
orders of magnitude faster”
:- I agree, but it is. You have no joins, no cursors, no indexes, no SQL to parse. If you want data to back this up got visit www.objectstore.net, www.objectivity.com or www.versant.com
“NAM from UK so what are you doing here”
:- Bating Grandpa
January 22, 2004 - 7:01 am UTC
given that these real financial systems are governed by international law and real ones have constraints like -- you MUST ensure each transaction is commited in two geographicaly separate databases (eg: to prevent something like a world trade center attack from wiping out a million dollar transfer) -- I think we'd be interested to hear about:
o the availability and recoverability requirements here. Whats the disaster recovery scenario here? how did you accomplish that? or is the data deemed "losable" -- or is the time to recovery measured in days instead of minutes.
o how many users use this concurrently -- finance systems typically do hundreds of TPS for hours on end. How about this?
o how big is this (I can use one row to hold 30,000,000,000 worth of stuff)
come on, some facts here. is this a mission critical, gotta run application or something that is "nice to have, if it disappears, oh well".
giving a user, who is very "ethnocentric" if you will -- very focused on themselves -- not the corporation as a whole -- is not always the "right thing". might make you a hero with that person, but a real pain with the company. Say that data is important, relevant, should be professionally managed so we can in fact recover it, restore it, have it in the event of a real failure (this is not a slam at the object database -- rather a slam at the notion of "hey, we'll just wing this puppy -- no need for dba's or anything like that")....
did you know, lots of data out there predates our existence. data is forever (he who owns the data owns the keys to the city). applications are like mayflies. they are born, live, breed, and die in a day. they come, they go. In the last 10 years -- I've seens dozens of applications come and go. The data underneath them? well, i'll be darned if it has not "survived".
and you have read:
</code>
http://www.slac.stanford.edu/BFROOT/www/Public/Computing/Databases/ <code>
right? that is not a single database, it is over 100 databases and took some 5 million lines of custom developed code to even fathom.
so, over 100 databases -- not one.
5,000,000 lines of custom code.
all to retrieve a blob at the end of the day.
interesting.
ahh, but the very very lack of what you deem evil (sql) is what makes these solutions "not very general purpose".
I deliver high speed, scalable, flexible as all get out old fashioned rdbms applications all of the time. all of the time. Hey - guess what -- you are using one right now (and look at amazon, yahoo, ebay, et. al. or does those guys just "not get it"?)
ObjectStore?
A reader, January 22, 2004 - 6:37 am UTC
I know an Object-Guru ("Java is Mc Donalds OO") who developed with his own company a big C++ ERP-system.
His only failure (he admits it) was, that he used ObjectStore for storing the data. The most time he got phone calls from frustrated customers, because their database hangs or crashed!
A reader, January 22, 2004 - 11:58 am UTC
“NAM from UK so what are you doing here
:- Bating Grandpa "
Kid this is not the forum for your imaginary talks :-))
Get evidence/results then well talk.. Here everybody
beleives in results proof.
January 22, 2004 - 7:44 pm UTC
funny thing is, with regards to "grandpa"
1970 - year the System R paper from IBM was made. described a language 'SQL' and the RDBMS concept
1970 - the year smalltalk, "the" OO language was invented....
hmm -- maybe - just maybe - pot calling kettle black.
what is consider new and cutting edge may just well be "like really really old".
funny -- goes back to Ada doesn't it? RDBMS = 70's = Ada = PL/SQL = Object Oriented. they all be about the same age. funny isn't it?
OH OH -- we need a new paradigm. wait, that's not right, "paradigm" is a 1990's term as well. It is dated. guess we just need something new?
A reader, January 22, 2004 - 12:00 pm UTC
OH YEAH!!!! I Love this forum.
The founder of the OOPL is Simula 67
Zlatko Sirotic, January 23, 2004 - 4:30 am UTC
"1970 - the year smalltalk, "the" OO language was invented...."
The founder of the OOPL is Simula 67, designed in 1967
by Kristen Nygaard and Ole-Johan Dahl
from the University of Oslo and the Norwegian Computing Center.
Best regards,
Zlatko Sirotic
some genuine care please
Gabriel, January 24, 2004 - 9:21 am UTC
CW said it ...
<quote>So, if you want to beat Msft you must play by their rules and Msft invest time & money in application developers. They put effort into trying to make programmers lives easier.</quote>
Right.
So, why can't we have what they have? I mean, you know I can be hard-headed at times, so forget about spending time ... how about some money?
I guess, I could spend those money for a MSDN subscription in order to get SS (never been able to find the link to their free developer download !?) ... but I'm sure they otherwise really care.
January 24, 2004 - 1:16 pm UTC
what do they have -- give me some info here.
what I heard from CW was "I want oracle to be exactly like ss. I don't want to have to learn anything about anything new. I want everything to be like ss"
so -- throw me a bone. give me a "for example", a list. something to work with.
We ain't going to mess up a really good concurrency model to be like them
We ain't going to dump plsql down to the level of t-sql.
We ain't going to remove our ability to scale really large.
But hey -- throw me a bone here.
Forgot to put some :-) somewhere in there.
Gabriel, January 25, 2004 - 3:16 pm UTC
I was expressing the opinion (not very well I guess) that
"genuine care" between for-profit corporations and developers doesnÂ’t quite exist (not very original, I know)Â… but on the subject of "common interests" Â… well Â… I was proposing the absence of a free-download for SS is maybe more indicative of the way they treat their developers (I may be wrong though Â… I donÂ’t travel to the "MS world" too often Â… but when I did, could never find it).
In retrospect, I guess my comment wasnÂ’t very constructive.
is it possible to do this?
A reader, February 02, 2004 - 4:09 am UTC
Hi
I have a pl/sql script which receives shell variables, I want to process this variable in a pl/sql array such as
filep="aa,ab"
DEFINE FILEPATH='&filep'
DECLARE
type l_array is table of varchar2(256);
l_file_path_ori varchar2(1000);
l_file_path l_array;
l_num_fs number;
l_nom_tabsp varchar2(30);
l_sql_str varchar2(2000);
BEGIN
l_file_path_ori := '''' || replace('&FILEPATH', ',', ''',''' ) || '''';
l_file_path := l_array(l_file_path_ori);
dbms_output.put_line(l_file_path(1));
END;
/
'aa','ab'
I dont get aa... do you know why?
February 02, 2004 - 7:49 am UTC
should be "obvious"?
l_file_path := l_array( some_variable );
regardless of the CONTENTS of some_variable -- l_file_path can have at most one element -- there is but one string in there!
You want l_file_path = l_array( &DEFINE_VARIABLE ); to get some literal string replacement happening:
define filep="aa,ab"
column X new_val filepath
select '''' || replace('&filep', ',', ''',''' ) || '''' X from dual;
DECLARE
type l_array is table of varchar2(256);
l_file_path l_array;
BEGIN
l_file_path := l_array(&FILEPATH);
dbms_output.put_line(l_file_path(1));
END;
/
Batch processing & Soft Parse
Vinnie, March 15, 2004 - 3:14 pm UTC
Tom,
We have a JAVA app that uses sendBatch & prepared Statments.
I have noticed in the trace file, that everytime
((OraclePreparedStatement)ps).sendBatch() is called the parse total is incremented. Is this expected? The developers insist the statements is only prepared once.
Thanks
March 15, 2004 - 3:39 pm UTC
can you give me a small example to investigate with? against emp and dept. I don't have any small "sendBatch"
(but the trace file would tell you for sure, you can read it, it'll show you exactly what is being parsed and when)
Trace
Vinnie, March 15, 2004 - 3:56 pm UTC
/*
* This sample shows how to use the batching extensions.
* In this example, we demonstrate the sue of the "sendBatch" API.
* This allows the user to actually execute a set of batched
* execute commands.
*
*/
// You need to import the java.sql package to use JDBC
import java.sql.*;
import oracle.sql.*;
// You need to import oracle.jdbc.driver.* in order to use the
// API extensions.
import oracle.jdbc.driver.*;
class SendBatch
{
public static void main (String args [])
throws SQLException
{
// Load the Oracle JDBC driver
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
// Connect to the database
Connection conn =
DriverManager.getConnection ("jdbc:oracle:thin:@waracle1:1521:perfuitt","salernov","salernov");
System.out.println("Connected");
Statement stmt = conn.createStatement ();
Statement stmt1 = conn.createStatement ();
stmt1.execute ("truncate table dept");
// Default batch value set to 50 for all prepared statements belonging
// to this connection.
((OracleConnection)conn).setDefaultExecuteBatch (2000);
stmt1.execute("alter session set events '10046 trace name context forever, level 12'");
PreparedStatement ps =
conn.prepareStatement ("insert into dept (e,a,b,c,create_date) values (?, rpad('X',400,'Z'), rpad('X',400,'Z'), rpad('X',400,'Z'), SYSDATE)");
int tot_rows = 0;
for (int i=1; i<1000;i++){
// ps =
// conn.prepareStatement ("insert into dept (e,a,b,c,create_date) values (?, rpad('X',400,'Z'), rpad('X',400,'Z'), rpad('X',400,'Z'), SYSDATE)");
tot_rows++;
ps.setInt(1, i);
// this execute does not actually happen at this point
int rows = ps.executeUpdate ();
// if ( rows >0 )
// System.out.println ( i + "Insert Executed");
//
// ps.close();
}
int rows = ps.executeUpdate ();
rows = ((OraclePreparedStatement)ps).sendBatch();
for (int i=1; i<1000;i++){
// ps =
// conn.prepareStatement ("insert into dept (e,a,b,c,create_date) values (?, rpad('X',400,'Z'), rpad('X',400,'Z'), rpad('X',400,'Z'),
//SYSDATE)");
tot_rows++;
ps.setInt(1, i);
// this execute does not actually happen at this point
int rows2 = ps.executeUpdate ();
// if ( rows >0 )
// System.out.println ( i + "Insert Executed");
//
// ps.close();
}
int rows2 = ps.executeUpdate ();
rows2 = ((OraclePreparedStatement)ps).sendBatch();
ps.setInt(1, 1000);
// this execute does not actually happen at this point
int rows3 = ps.executeUpdate ();
rows3 = ps.sendBatch();
ps.setInt(1, 1000);
// this execute does not actually happen at this point
int rows3 = ps.executeUpdate ();
rows3 = ((OraclePreparedStatement)ps).sendBatch();
System.out.println ("Total Rows Inserted: " + tot_rows );
// Execution of both previously batched executes will happen
// at this point. The number of rows updated will be
// returned by sendBatch.
ps.close ();
conn.close ();
}
}
insert into dept (e,a,b,c,create_date)
values
(:1, rpad('X',400,'Z'), rpad('X',400,'Z'), rpad('X',400,'Z'), SYSDATE)
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 3 0.01 0.00 0 0 0 0
Execute 3 0.25 1.42 0 313 1246 2001
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 6 0.26 1.42 0 313 1246 2001
Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 197
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 5 0.00 0.00
SQL*Net message from client 5 0.19 0.24
SQL*Net more data from client 4 0.00 0.00
log buffer space 6 0.42 1.16
log file sync 3 0.46 0.94
********************************************************************************
Is the parse count incremented everytime the ((OraclePreparedStatement)ps).sendBatch() is called?
March 15, 2004 - 6:12 pm UTC
Yes, it appears that every explicit "sendBatch" or "commit" will cause a subsequent soft parse.
If you set the batch size really low (send the executes way up) the parses stay low. If you add lots of commits, they go way up. if you add lots of sendBatches, they go way up.
Not sure "why", but using update batching -- you shouldn't necessarily need to use sendBatch. It is unfortunate (not sure of the implementation needs of this) but better then parse/execute for each row.
To minimize the parsing, do not invoke sendBatch. Also, consider having session_cached_cursors set as well.
Need your help
Ralph, March 16, 2004 - 1:30 am UTC
Hi Tom,
Suppose if I have an array like
sql> declare
type t is table of number;
array t := t(1,2,3);
I would like to pass this array to a procedure and get each
element of the array multiplied by a number i.e say 2.How to
do that?Do I have to use Java?Is there any way in PL/SQL to
accomplish that?
Need your help over there.
Please do reply.
March 16, 2004 - 7:43 am UTC
you have to make the type visible. right now there is exactly ONE block of code on the planet that can see it -- that anonymous block. No one else knows about that type.
You would code like this:
ops$tkyte@ORA9IR2> create or replace type numArray as table of number
2 /
Type created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create or replace procedure p( p_data in out numArray )
2 as
3 begin
4 for i in 1 .. p_data.count
5 loop
6 p_data(i) := p_data(i) * 2;
7 end loop;
8 end;
9 /
Procedure created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> declare
2 l_data numArray := numArray(1,2,3);
3 begin
4 for i in 1 .. l_data.count
5 loop
6 dbms_output.put_line( l_data(i) );
7 end loop;
8 p( l_data );
9
10 dbms_output.put_line( 'after....' );
11 for i in 1 .. l_data.count
12 loop
13 dbms_output.put_line( l_data(i) );
14 end loop;
15 end;
16 /
1
2
3
after....
2
4
6
PL/SQL procedure successfully completed.
In this case, you can "hide" the type in a package as well if you like:
ops$tkyte@ORA9IR2> create or replace package demo_pkg
2 as
3 type numArray is table of number;
4
5 procedure p( p_data in out numArray );
6 end;
7 /
Package created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create or replace package body demo_pkg
2 as
3
4 procedure p( p_data in out numArray )
5 as
6 begin
7 for i in 1 .. p_data.count
8 loop
9 p_data(i) := p_data(i) * 2;
10 end loop;
11 end;
12
13 end;
14 /
Package body created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> declare
2 l_data demo_pkg.numArray := demo_pkg.numArray(1,2,3);
3 begin
4 for i in 1 .. l_data.count
5 loop
6 dbms_output.put_line( l_data(i) );
7 end loop;
8 demo_pkg.p( l_data );
9
10 dbms_output.put_line( 'after....' );
11 for i in 1 .. l_data.count
12 loop
13 dbms_output.put_line( l_data(i) );
14 end loop;
15 end;
16 /
1
2
3
after....
2
4
6
PL/SQL procedure successfully completed.
<b>No java needed or desired here...</b>
My Favorite MS Sql Feature
Terry, March 16, 2004 - 8:51 am UTC
SS Licenses can be traded in at par for Oracle Licenses. Think of it like the "Lemon Law" when you purchase a car that just does not work for you and the other guy throws you a life preserver.
I have to admit I am watching a "crew" try to do a 1 TB SS Data warehouse and it is funny. No performance and everybody running around saying "can't you just add an index or something". It's a real bitch when you can't find anymore registry keys to play with and time's up. You gotta love the MS Sales idiot who fills these guys full of BS about 32 Bit this, 64 Bit that, 2003 threading models, yadda, yadda, yadda just long enough to get their money and make them sink cash into new hardware as well.
The trick is to do the switch before you go broke or destroy the data. The problem is most of these guys die trying to make it work and the credability of another MIS project goes down the drain. But it is funny to watch ...
"at the end of the day" - - commonly used here
Jan, March 30, 2004 - 2:08 am UTC
March 30, 2004 - 8:15 am UTC
"Absolutely", I will work "24/7" to "address the issue" "going forward". It was "awesome" to have that pointed out I'll work to recitify it. "Basically" you'll have to "bear with me" while I try to "blue sky" a method to avoid cliches. It "literally" "boggles the mind" how often it happens (sort of an "ongoing" problem) -- but I feel I'm "between a rock and a hard place" at times (I know, I know, "it's not rocket science") rushing to answer the questions in a conversational tone, thats the "bottom line". Guess I thought the cliches were "value added" text -- making it sound more like a discussion.
"The fact of the matter is" however -- that "I hear what you are saying", we are "singing from the same hymn sheet". I'll work to "prioritise" this, but "to be honest with you", I cannot come up with a "ballpark figure" as to how long the problem might persist. I'll try on a daily "basis" to cut down on their use, but it'll be "pushing the envelope" to think it'll happen overnight. "In terms of" a reasonable timeline -- I'm thinking "around" 2 or 3 weeks, but I'd give it "up to" a month or so. Unless someone "moves the goal-posts" on me of course -- that would change everything. I'm sure some "out of the box thinking" (maybe I can put a trigger on the table to catch them....) might apply. Guess it is a "glass half full/empty" problem really -- some people would just read over them as if they weren't there....
We'll "touch base" on this for sure.
RE:"at the end of the day" - - commonly used here
A reader, March 30, 2004 - 8:36 am UTC
That was a good one :-)
let`s hope that....
Jan, March 30, 2004 - 9:18 am UTC
... SQL and PL/SQL commands (SELECT, UPDATE,INSERT..)
will not become cliches.
Creating Arrays.
Russell, May 28, 2004 - 1:30 am UTC
Hi Tom,
I entered the following line into sqlplus
create or replace type numArray as table of number
*
ERROR at line 1:
ORA-00439: feature not enabled: Objects
I take it that something needs to be installed.
What do I need to ask the DBA to add?
What will they need to do? ie does the database need to be bounced etc
Thanks.
May 28, 2004 - 8:08 am UTC
what version?
Objects were a "for fee" option to 8.0. If you did not license it, they are not there.
In 8i -- every Oracle database would have them.
Array vs SQL
Rob H, August 09, 2004 - 3:17 pm UTC
I'm having a bit of a difficulty choosing between using sql or a fuction with an array to accomplish the job.
I've come up with this Query for testing
select
* from
(
select
ProductMax,
lead(Product,0) over (order by price desc) Product1,
lead(qty,0) over (order by price desc) Product1_Qty,
lead(price,0) over (order by price desc) Product1_Price,
lead(Product,1) over (order by price desc) Product2,
lead(qty,1) over (order by price desc) Product2_Qty,
lead(price,1) over (order by price desc) Product2_Price,
lead(Product,2) over (order by price desc) Product3,
lead(qty,2) over (order by price desc) Product3_Qty,
lead(price,2) over (order by price desc) Product3_Price,
least(ProductMax,lead(qty,0) over (order by price desc)) Product1_pick_qty,
least(ProductMax-least(ProductMax,lead(qty,0) over (order by price desc)),lead(qty,1) over (order by price desc)) Product2_pick_qty,
least(ProductMax-least(ProductMax,lead(qty,0) over (order by price desc)) - least(ProductMax-least(ProductMax,lead(qty,0) over (order by price desc)),lead(qty,1) over (order by price desc)) ,lead(qty,2) over (order by price desc)) Product3_pick_qty
from
(
select 'Cheap Product' Product, 3 qty, 10 price from dual
union
select 'Mid Product' Product, 5 qty, 20 price from dual
union
select 'Exp Product' Product, 4 qty, 30 price from dual
) TransData,
(select 8 ProductMax from dual) MaxData )
where rownum=1
What it does is recieve transactional data and a max quantity, sorts the transactions by price, largest to smallest, and select max qty available for each product within the max quantity for all products. It tries to use all of the max qty available using the product qty's. Should I be using an array and a function. I'm a SQL guy myself.
August 09, 2004 - 8:07 pm UTC
is that the "real query" ?
if you were trying to do a simple transpose (pivot), we might just opt for max(decode(....))
rob h, August 11, 2004 - 3:52 pm UTC
The query is a test of plausibility. Play with the quantities (Qty) of the products and prices. The purpose of the query was to order the products in terms of price and remove qty from the ProductMax so that the total quantity was less than or equal to the ProductMax. Thus if the ProductMax is 8, then it will pick as many of the Highest Priced qty as it can (4), then the next highest and so on, but ensuring that the total picked does not exceed the ProductMax.
The idea is for a purchase rebate. Lets say you but Pencils, erasers and paper (X values). Then you become eligible for a rebate on 8 product (ProductMax). The point is to give you a rebate % on up to 8 products.
Product - X - Y
Pencils - 4 - 4
Paper - 5 - 4
Erasers - 3 - 0
The Y is the products that qualify for the rebate.
My initial question was what the best method of calculating this should be.
1. Use the query above
2. Use a function with Arrays
3. Use a function with a cursor
August 12, 2004 - 7:51 am UTC
my preference is always (my four laws of database, like Asimov's three laws of robotics -- which got extended to 4):
a) if you can do it in a single (commented) SQL statement, do it.
b) if you cannot do it in a single sql statement, do it with as little plsql
as possible
c) if you cannot do it in plsql (rare), use the tiniest snippect of java in a
stored procedure you can
d) if you cannot do it in plsql or java (primarily for performance reasons), the
smallest C extproc you can get would be next
So, if that sql statement works for you -- put a nice comment block in front of it for furture generations (just like you would for the equally obscure procedural approach) and go for it.
Arrays in condition?
Tony, November 08, 2004 - 7:12 am UTC
Tom!
Everything is as amusing and interesting AND useful as usual - top notch!!!
Anyway - I get an array (emp_id_array) from java into a stored procedure, and what I want to do is something like this:
INSERT INTO employee_temp (emp_id, first_name, last_name)
VALUES (SELECT employee_id, first_name, last_name FROM employee WHERE employee_id NOT IN emp_id_array.emp_id);
How can I get that "exclude the emp_id's in this array" clause in this the simplest way?
Thanks again!
/Tony
November 08, 2004 - 4:40 pm UTC
ops$tkyte@ORA9IR2> create or replace type arrayType as table of number
2 /
Type created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> drop table emp;
Table dropped.
ops$tkyte@ORA9IR2> create table emp as select * from scott.emp;
Table created.
ops$tkyte@ORA9IR2> exec dbms_stats.gather_table_stats( user, 'EMP' );
PL/SQL procedure successfully completed.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> drop table emp_tmp;
Table dropped.
ops$tkyte@ORA9IR2> create table emp_tmp as select * from scott.emp where 1=0;
Table created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> declare
2 l_data arrayType := arrayType(7788,7566);
3 begin
4 insert into emp_tmp
5 select *
6 from emp
7 where empno not in ( select column_value
8 from TABLE( cast( l_data as arrayType ) )
9 where column_value is not null
10 and rownum >= 0 );
11 end;
12 /
PL/SQL procedure successfully completed.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select count(*) from emp;
COUNT(*)
----------
14
ops$tkyte@ORA9IR2> select count(*) from emp_tmp;
COUNT(*)
----------
12
What if we do this dynamic...
Tony, November 12, 2004 - 11:40 am UTC
Hope that I am posting on the right topic here now that I am going with a DynamicSQL/Nullable invalues/Arrays question.
create or replace procedure insertarray (deselectedarray desarray, firstname varchar2, lastname varchar2)
as
ins_stmt varchar2(512);
begin
ins_stmt = 'INSERT into temp_emp (employee_id, first_name, last_name)' ||
'(SELECT employee_id, first_name, last_name FROM Employee
WHERE 1=1 ';
if (deselectedarray IS NOT NULL)
then
ins_stmt := ins_stmt || 'AND "employee_id NOT IN select employee_id from deselectedarray)" ';
end if;
if (lastname IS NOT NULL)
then
ins_stmt := ins_stmt || 'AND last_name = ''' || lastname || '''';
end if;
if (firstname IS NOT NULL)
then
ins_stmt := ins_stmt || 'AND first_name = ''' || firstname || '''';
end if;
ins_stmt := ins_stmt || ')';
execute immediate ins_stmt;
commit;
end;
Is there any way that we can do this with the array?
Also is there any point in using bind variables in this dynamic sql statement - I mean we'll always have to parse this one anyway, right?
Thanks! :)
/Tony
November 12, 2004 - 1:35 pm UTC
ops$tkyte@ORA9IR2> create or replace type myArrayType as table of number
2 /
Type created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> variable x refcursor
ops$tkyte@ORA9IR2> declare
2 l_data myArrayType := myArrayType(1,3,5);
3 begin
4 open :x for select * from table(cast(l_data as myArrayType));
5 end;
6 /
PL/SQL procedure successfully completed.
ops$tkyte@ORA9IR2> print x
COLUMN_VALUE
------------
1
3
5
Tony, November 14, 2004 - 3:05 am UTC
Tom,
I got that part with the table and cast, but I can't seem to do bind the array type into the statement dynamically in runtime ... or what have I missed... or am I on the right path at all here?
Thanks,
/Tony
November 14, 2004 - 10:01 am UTC
ops$tkyte@ORA9IR2> create or replace type myArrayType as table of number
2 /
Type created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create table emp as select empno, ename, job from scott.emp where 1=0;
Table created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create or replace procedure doit( p_array in myArrayType, p_fname in varchar2, p_lname in varchar2 )
2 as
3 l_stmt long := 'insert into emp (empno, ename, job)
4 select empno, ename, job
5 from scott.emp
6 where 1=1 ';
7 begin
8 if ( p_fname is not null )
9 then
10 l_stmt := l_stmt || ' and ename = :p_fname ';
11 else
12 l_stmt := l_stmt || ' and :p_fname is null ';
13 end if;
14 if ( p_lname is not null )
15 then
16 l_stmt := l_stmt || ' and ename = :p_lname ';
17 else
18 l_stmt := l_stmt || ' and :p_lname is null ';
19 end if;
20
21 if ( p_array is not null )
22 then
23 l_stmt := l_stmt || ' and empno not in ( select * from table(cast( :p_array as myArrayType ) ) )';
24 execute immediate l_stmt using p_fname, p_lname, p_array;
25 else
26 execute immediate l_stmt using p_fname, p_lname;
27 end if;
28 dbms_output.put_line( sql%rowcount || ' rows inserted' );
29 end;
30 /
Procedure created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> exec doit( null, 'KING', null );
1 rows inserted
PL/SQL procedure successfully completed.
ops$tkyte@ORA9IR2> exec doit( myArrayType( 7369, 7499, 7521, 7566, 7654, 7698, 7782, 7788 ), null, null );
6 rows inserted
PL/SQL procedure successfully completed.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select * from emp;
EMPNO ENAME JOB
---------- ---------- ---------
7839 KING PRESIDENT
7839 KING PRESIDENT
7844 TURNER SALESMAN
7876 ADAMS CLERK
7900 JAMES CLERK
7902 FORD ANALYST
7934 MILLER CLERK
7 rows selected.
<b>is one approach to this...</b>
Brilliant...
Tony, November 19, 2004 - 10:02 am UTC
... but I was doing some "Monday Programming" and I thought I was doing it like you did ... but discovered that I was actually not ... when I saw your tip/comment.
Anyway - works like a charm now
Thanks,
/Tony
Alex, September 07, 2005 - 5:57 pm UTC
Hi Tom,
If I could add a 6 for rate of this response I would. I have some important questions concerning passing arrays to stored procedures:
1.) If I have a bunch of records to pass to my procedure, and the procedure contains a lot of logic that would be too much to bump up into the application for the use of preparedstatements with batch updates, is sending arrays the only game in town? ("Bunch" in this case i'll define as enough rows that would be foolish to make x number of procedure calls across the network.)
2.) Let's say I have hundreds of stored procedures already existing, would we have to make changes to all of them to take an array?
This probably also means that we will run into problems where array processing would make sense in some areas of the app, but in other places where the same procedure is called, it would not make sense.
I am grateful for your advice. I would like to know how you handle this type of thing. I am very unfamiliar with Java but I do know that the way we do things now, which is to call the stored procedure for every record to be processed is crazy. Thanks a lot.
ps As I was writing this one of our application guys came over to me to explain that our apps framework doesn't support preparedstatements because of their own brand of jdbc code that they edited so they can validate database integrity via the application by determining who has what business object open where the business object is a dynamic sql statement or SP and they use the keys being used by the object to determine whether or not to lock another user out of the same record. "They" are the people who worked on this project before we took over the contract. Must be why they used stringBuffer strings for everything. I'm telling you this to explain why it wasn't done right the first time and also to see where that ranks on your lists of stories about the worst designed apps ever.
September 08, 2005 - 7:48 am UTC
1) thank goodness data logic is in the database :)
You could:
o send plsql tables
o send collections of object types (arrays of records in effect)
o use a global temporary table, client batch inserts into this table and plsql bulk processes it.
2) you can always write a "wrapper" layer on top that recieves the array and then calls existing routine slow by slow - but it would make sense to look at some of the time consuming operations and see how much code you can erase.
ouch on that last paragraph.
Alex, September 08, 2005 - 11:05 am UTC
Thank you for the reply.
Although I am unfamiliar with all the approaches you suggested, the second one you mentioned about object type collections sounds the most painless. This requires the stored procedure to take an array correct? How do you prefer to do things?
I thought I read somewhere you said plsql tables aren't recognized outside of plsql and hence can't be referenced from Java nor do they handle binds? But sql is recognized by all because it's in the data dictionary? In case you can't tell I'm not well versed in communicating from Java to Oracle. Does Menon's new JDBC book talk about these subjects? I just got it and it looks promising.
September 08, 2005 - 3:50 pm UTC
actually, that is the most painful one!
plsql tables of RECORDS are not recognized outside of plsql, plsql tables of SCALARS are...
Menon's JDBC book does cover this yet -- definition.
If I had to rank them effort wise from easy to hard:
a) global temporary table
b) plsql tables of scalars
c) using jpublisher to create java mapping classes to support collections of objects
Alex, October 24, 2005 - 4:59 pm UTC
Tom,
Do you know where I can find a complete example of option b.)? I'm not sure what kind of type my procedure should take for a pl/sql table. I'm also not sure what I should be passing from java either, whether it be an array or whatever. Thanks.
October 25, 2005 - 1:25 am UTC
Alex, October 25, 2005 - 12:02 pm UTC
Ok I'm getting there, by my procedure won't compile.
I have yet to find an example of passing IN a pl/sql table, so I'm of wingin it. I hope you can straighten me out.
SQL*Plus: Release 9.2.0.1.0 - Production on Tue Oct 25 11:48:42 2005
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.6.0 - Production
With the OLAP and Oracle Data Mining options
JServer Release 9.2.0.6.0 - Production
SQL> create or replace procedure pass_me_a_plsql_table (p_table In varchar2)
2 as
3
4 -- TYPE plsql_table is table of varchar2(4000) index by binary_integer;
5 -- l_plsql_table plsql_table;
6
7 begin
8 forall i in 1..p_table.count
9 insert into t (mjfcn) values (p_table(i));
10 end loop;
11 end pass_me_a_plsql_table;
12 /
Warning: Procedure created with compilation errors.
SQL> show err
Errors for PROCEDURE PASS_ME_A_PLSQL_TABLE:
LINE/COL ERROR
-------- -----------------------------------------------------------------
10/6 PLS-00113: END identifier 'LOOP' must match
'PASS_ME_A_PLSQL_TABLE' at line 1, column 11
11/1 PLS-00103: Encountered the symbol "END"
SQL>
Sorry to bug you on your trip.
October 26, 2005 - 7:34 am UTC
there is no "end loop" to a forall
forall i in 1 .. p_table.count
insert ....;
but p_table in your example isn't a TABLE, it is string - not sure where you are going with that?
Alex, October 26, 2005 - 9:13 am UTC
Ok thanks, I did get it working. I found a good example on metalink using a package procedure. I couldn't get it to working using a stand alone procedure, for the reason you pointed out (what to with my IN parameter). If I have a plsql table coming IN from java, I would have to create a plsql table type, and use that as the data type in my procedure is that correct? But what I don't understand is that apparently you don't create associative arrays as you would a VARRAY or nested table.
They are within the program, where as the others are actually part of a table on disk?
So I guess my final question on this is, if I wanted to do a stored procedure using an incoming plsql table, would you declare the type in the procedure as use it in the incoming parameter like this:
create or replace PROCEDURE sp_array_test (p_table IN plsql_table)
is
type plsql_table is table of varchar2(100) index by binary_integer;
Thanks a lot, I find collections confusing.
October 26, 2005 - 12:30 pm UTC
Yes, you would define the plsql table type in plsql and use that.
Yes, associative arrays (index by tables that are indexed by something other than a number) are PLSQL only types.
You should use packages, you define the plsql table type in the package specificiation.
Alex, October 26, 2005 - 10:49 am UTC
I spoke too soon. I think I may have wasted my time. We are using a jdbc thin driver. It seems you need a jdbc oci driver to send plsql tables from java, is this correct? I'm getting an unsupported feature error. Could you give me my list of options for this please, whether or not there are none OCI methods I can use (I didn't see any) or if I have to switch drivers (I have no idea what repercussions would ensue), thanks again.
October 27, 2005 - 3:06 am UTC
yes, you need to use the thick drivers with the 9i drivers
but 10g added support for the thin drivers. I just tested.
create or replace package demo_pkg
as
type arry_type is table of varchar2(32000) index by binary_integer;
end;
/
CREATE OR REPLACE PROCEDURE SPMBTEST3 (
VAR1 IN VARCHAR2,
VAR2 IN demo_pkg.ARRY_TYPE,
VAR3 OUT demo_pkg.ARRY_TYPE)
IS
BEGIN
DECLARE
wk_Subject VARCHAR2(64);
BEGIN
VAR3(1) := 'in2';
var3(2) := 'in3';
var3(3) := 'in4';
var3(4) := 'in5';
return;
EXCEPTION
WHEN OTHERS THEN
RETURN ;
END;
END;
/
$ cat spmbtest.java
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;
class spmbtest
{
public static void main (String args []) throws SQLException, ClassNotFoundException
{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@localhost:1521:ora10g","scott", "tiger");
run( conn );
conn.close();
}
static void run(Connection conn) throws SQLException
{
System.out.println ("SPMBTEST_TEST");
OracleCallableStatement
spmbtest=(OracleCallableStatement)conn.prepareCall("{ call SPMBTEST3( ?, ?, ? ) }");
String[] values = { "xy","xd","xe" };
int maxLen = values.length;
int currentLen = values.length;
int elemSqlType = OracleTypes.VARCHAR;
int elemMaxLen = 10;
int maxOutLen = 20;
spmbtest.setString( 1, "12345" );
spmbtest.setPlsqlIndexTable (2, values, maxLen, currentLen, elemSqlType, elemMaxLen);
spmbtest.registerIndexTableOutParameter (3, maxOutLen, elemSqlType, elemMaxLen);
System.out.println("going to run" );
spmbtest.executeQuery();
Datum[] outvalues = spmbtest.getOraclePlsqlIndexTable (3);
for (int i=0; i<outvalues.length; i++) System.out.println (outvalues[i].toString());
spmbtest.close();
}
}
No go, read it again
J, October 26, 2005 - 1:00 pm UTC
create or replace PROCEDURE sp_array_test (p_table IN plsql_table)
is
type plsql_table is table of varchar2(100) index by binary_integer;
BEGIN
NULL;
END;
1 Create procedure, executed in 0.14 sec.
1 37 PLS-00201: identifier 'PLSQL_TABLE' must be declared
PL/SQL: Compilation unit analysis terminated
Total execution time 0.2 sec.
October 27, 2005 - 3:28 am UTC
create or replace package my_pkg
as
type plsql_table is table of varchar2(100) index by binary_integer;
procedure sp_array_test( p_table in plsql_table );
end;
/
create or replace package body my_pkg
USE PACKAGES.... (I see the sp_, that is a sqlserver'ism - forget your sqlserver ways of doing things, every database is different - in Oracle use packages for all real code)
you have to create the SQL type first
Tyler, October 26, 2005 - 1:09 pm UTC
if you're going to be referencing the type as a parameter to the procedure, you have to have it created.
ME_DEV?create type plsql_table is table of varchar2(100)
2 /
Type created.
ME_DEV?
ME_DEV?
ME_DEV?
ME_DEV?
ME_DEV?create or replace PROCEDURE sp_array_test (p_table IN plsql_table)
2 is
3 type plsql_table is table of varchar2(100) index by binary_integer;
4 BEGIN
5 NULL;
6 END;
7 /
Procedure created.
This would be much better in a package where you could just declare the type plsql_table in the package spec, instead of creating a SQL type.
My 2 cents.
Alex, October 27, 2005 - 1:32 pm UTC
We are on 9i, not 10g. I cannot just change drivers either, that is why I said I modified the code to attempt to work with a thin driver. I'm guessing from your liberal use of question marks you are perplexed by something I did?
October 27, 2005 - 2:09 pm UTC
you can switch out the thin drivers in a second?
the 10g thin drivers work with 9i and such. Why not use the 10g drivers with their "better functionality"?
Else you'll be using collections and that is slightly more awkward.
Alex, October 27, 2005 - 2:16 pm UTC
You've worked on many government projects correct? To change something like that is a huge ugly mess, they must meet X number of security checks etc etc....It's something I have no control over, I'm only 25 I have no pull and I wouldn't even know how to do that even if I could (I could learn sure...).
Can't I just use java.sql methods instead of OCI? Does my code as posted need a different driver?
October 27, 2005 - 2:48 pm UTC
</code>
http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:712625135727 <code>
there are examples of java passing collections to plsql (watch your CASE, ARRAY, not Array, type names UPPER in the string - not lower)
Also, not sure what the result set .getArray is for?
(ps: i removed your code snippet to which I'm refering, just noticed it has a real IP address in it and a username/password)...
Alex, October 28, 2005 - 9:04 am UTC
I ran into a few other problems but I got through it, thank you. The rs.getArray(1) was to get results from the query I was using, then use that as my array to pass to Oracle. I was doing it wrong though.
That database url stuff I posted was made up, but thanks for keeping an eye out.
Wow I am impressed
Nestor De Castro, October 31, 2005 - 7:25 am UTC
How to array insert to temporary table
Charlie Zhu, February 16, 2006 - 8:03 pm UTC
Hi Tom,
Based on Alex Q&A,
o use a global temporary table, client batch inserts into this table and plsql bulk processes it.
and
what if huge IN-list.
</code>
http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:210612357425 <code>
Could you please give a complete Java array insert example?
and there are other options available:
1)Oracle Update Batching (Oracle 10.2 JDBC)
file:///C:/oracle/10.2doc/B19306_01/java.102/b14355/oraperf.htm#i1056232
2)JDBC RowSets
file:///C:/oracle/10.2doc/B19306_01/java.102/b14355/jcrowset.htm#CIHBFAAE
3)Use CLOB to replace varchar2(4000) as Str2tbl input parameter.
I think 1) and 2) both to reduce network round trip, do batch update.
What do you think of them? which one is better?
Thanks a lot.
Unable to execute function with record types as in parameter
Reader, July 18, 2006 - 5:13 am UTC
CREATE TABLE cmtm_collateral_owner_defn(version_no NUMBER,collateral_id VARCHAR2(20),relationship VARCHAR2(10),owner_ssn VARCHAR2(10))
/
CREATE TYPE cmtm_collateral_owner_defn_ty AS OBJECT(relationship VARCHAR2(10),owner_ssn VARCHAR2(10))
/
CREATE TYPE cmtm_collateral_type IS TABLE OF cmtm_collateral_owner_defn_ty
/
INSERT INTO CMTM_COLLATERAL_OWNER_DEFN ( VERSION_NO, COLLATERAL_ID, RELATIONSHIP,
OWNER_SSN ) VALUES (
1, 'CID1', 'XXX', 'AAA');
COMMIT
/
CREATE OR REPLACE FUNCTION fn_collateral1 (
p_version_no IN NUMBER,
p_collateral_id IN VARCHAR2,
p_relation_ownerssn IN cmtm_collateral_type,
p_error_code OUT VARCHAR2
)
RETURN BOOLEAN
IS
COUNT NUMBER;
BEGIN
SELECT COUNT (1)
INTO COUNT
FROM cmtm_collateral_owner_defn
WHERE version_no = p_version_no
AND collateral_id = p_collateral_id
AND relationship = p_relation_ownerssn (1).relationship
AND owner_ssn = p_relation_ownerssn (1).owner_ssn;
RETURN TRUE;
EXCEPTION
WHEN OTHERS
THEN
p_error_code := SQLERRM;
RETURN FALSE;
END;
/
now iam facing problem in running this program.
iam unable to execute and check it.
can you please help me out.
DECLARE
RetVal BOOLEAN;
P_VERSION_NO NUMBER;
P_COLLATERAL_ID VARCHAR2(200);
P_RELATION_OWNERSSN cmtm_collateral_type;
P_ERROR_CODE VARCHAR2(200);
BEGIN
P_VERSION_NO := 1;
P_COLLATERAL_ID := 'CID1';
P_RELATION_OWNERSSN.relationship:='XXX';
P_RELATION_OWNERSSN.owner_ssn:='AAA';
P_ERROR_CODE := NULL;
RetVal := SCOTT.FN_COLLATERAL1 ( P_VERSION_NO, P_COLLATERAL_ID, P_RELATION_OWN
COMMIT;
END;
ORA-06550: line 11, column 23:
PLS-00302: component 'RELATIONSHIP' must be declared
ORA-06550: line 11, column 3:
PL/SQL: Statement ignored
ORA-06550: line 12, column 23:
PLS-00302: component 'OWNER_SSN' must be declared
ORA-06550: line 12, column 3:
PL/SQL: Statement ignored
thanks in advance
July 18, 2006 - 8:31 am UTC
CREATE TYPE cmtm_collateral_type IS TABLE OF cmtm_collateral_owner_defn_ty
cmtm_collateral_type is a collection, not a "scalar record"
cmtm_collateral_owner_defn_ty is the scalar record type. Your function takes an ARRAY, not a single "record"
Passing Object as parameter in a Function Call
Arindam Mukherjee, November 02, 2006 - 2:56 am UTC
Respected Mr. Tom
ItÂ’s my humble request to you please to see the following code and kindly help me get the answer. I have used "Ref" handle in the definition of second object but could not find my answer to any oracle document.
CREATE TYPE ARIN_DepT_OBJ AS OBJECT
(
deptno NUMBER(2),
dname VARCHAR2(14),
loc VARCHAR2(13)
)
/
CREATE TABLE ARIN_DEPT_OBJ_TAB OF ARIN_DEPT_OBJ
AS
SELECT ARIN_DEPT_OBJ(deptno, dname, loc) FROM dept
/
INSERT INTO ARIN_DEPT_OBJ_TAB VALUES (2,'Training','Kolkata')
/
CREATE TYPE ARIN_EMP_OBJ 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 REF ARIN_DEPT_OBJ
)
/
CREATE TABLE ARIN_EMP_OBJ_TAB OF ARIN_EMP_OBJ
AS
SELECT ARIN_EMP_OBJ(e.empno, e.ename, e.job, e.mgr, e.hiredate, e.sal,
e.comm, (SELECT REF(d) FROM ARIN_DEPT_OBJ_TAB d WHERE d.deptno = e.deptno))
FROM emp e
/
Q 1. Now how can I select record from ARIN_EMP_OBJ_TAB? I have already used "SELECT * FROM ARIN_EMP_OBJ_TAB;" but the output for DEPTNO is found very opaque as it uses "ref"?
Q 2. How can I pass object to the following function as a parameter in PL/SQL block? In oracle document, I have had but "REF" is not declared in that example in any object where in my example "REF" has been used in the structure of second object. Please write a snippet of code to understand.
CREATE OR REPLACE FUNCTION wages (e ARIN_EMP_OBJ) RETURN NUMBER AS
LANGUAGE JAVA
NAME 'Paymaster.wages(oracle.sql.STRUCT) return BigDecimal';
/
November 02, 2006 - 7:10 am UTC
q1) you already know how to select from it? if you want to see what the ref points to, look up "deref"
q2) not sure what you are trying to do here
In short, my personal recommendation would be
use relational structures, learn relational, you'll never be sorry you did.
nested table processing
A reader, November 01, 2011 - 6:56 am UTC
Hi tom,
I have requirement on array processing as follows
table and insert scripts below..
SQL> create table c(pk1 varchar2(10),pk2 varchar2(10),serialno number(10,2),ind var
at,val2 float);
Table created.
SQL> insert into c values('a1','b1',1,'G',10.5,11.5);
1 row created.
SQL> insert into c values('a1','b1',2,'G',12.5,12.5);
1 row created.
SQL> insert into c values('a1','b1',3,'H',13.5,10.5);
1 row created.
SQL> insert into c values('a1','b1',4,'G',18.5,15.5);
1 row created.
SQL> insert into c values('a1','b1',5,'G',21.5,18.5);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from c;
PK1 PK2 SERIALNO I VAL1 VAL2
---------- ---------- ---------- - ---------- ----------
a1 b1 1 G 10.5 11.5
a1 b1 2 G 12.5 12.5
a1 b1 3 H 13.5 10.5
a1 b1 4 G 18.5 15.5
a1 b1 5 G 21.5 18.5
SQL> set serveroutput on;
SQL> declare
2 type t is table of number;
3 val1_tab t;
4 val2_tab t;
5 begin
6 select val1,val2 bulk collect into val1_tab,val2_tab from c;
7 dbms_output.put_line(val1_tab(1)||' '||val1_tab(2)||' '||val1_tab(3)||' '||val1_tab(4)||' '||va
l1_tab(5));
8 dbms_output.put_line(val2_tab(1)||' '||val2_tab(2)||' '||val2_tab(3)||' '||val2_tab(4)||' '||va
l2_tab(5));
9 end;
10 /
10.5 12.5 13.5 18.5 21.5
11.5 12.5 10.5 15.5 18.5
PL/SQL procedure successfully completed.
If ind is H then I have to increment val1 and val2(13.5 and 10.5)of the serial number(3 where ind =’H’ till we reach the next serial number values (4 in this case) val1 and val2 (i.e 18.5 and 15.5) and populate them in to the respective nested tables…means
I need to populate the values in to nested tables as follows
In val_tab1ïƒ 10.5 12.5 13.5 14.5 15.5 16.5 17.5 18.5 21.5
In val_tab2ïƒ 11.5 12.5 10.5 11.5 12.5 13.5 14.5 15.5 18.5
How can I achieve this ?Is it possible using single sql or ??
November 02, 2011 - 3:03 am UTC
In your example:
a1 b1 3 H 13.5 10.5
a1 b1 4 G 18.5 15.5
both val1 and val2 for serialno = 3 are exactly 5 away from serialno 4.
Is that always the case - or could val1 be say 5 away and val2 be 10 away - and if so, what is the expected outcome.
Also, will val1/val2 always be an integer number of values away from the next one or could val1/val2 be 5.5 away for example - and if so, what is the expected outcome.
Array Processing
A reader, November 02, 2011 - 3:44 am UTC
Hi Tom,
1.Val1 and val2 cannot be 10 away and 5 away for ex will be always either val(10 away),val2(10away) meaning both will be same integer values away.
2.val1 and val2 be always integer number of values away.
Thanks
November 02, 2011 - 4:18 am UTC
ops$tkyte%ORA11GR2> with data as
2 (
3 select pk1, pk2, serialno, ind, val1, val2,
4 lead(val1) over (order by serialno) next_val1
5 from c
6 )
7 select pk1, pk2, serialno, ind, val1+column_value, val2+column_value
8 from data,
9 table( cast( multiset( select level-1 l from dual connect by level <=
10 case when ind = 'H' then next_val1-val1
11 else 1
12 end ) as sys.odciNumberList ) )
13 /
PK1 PK2 SERIALNO I VAL1+COLUMN_VALUE VAL2+COLUMN_VALUE
---------- ---------- ---------- - ----------------- -----------------
a1 b1 1 G 10.5 11.5
a1 b1 2 G 12.5 12.5
a1 b1 3 H 13.5 10.5
a1 b1 3 H 14.5 11.5
a1 b1 3 H 15.5 12.5
a1 b1 3 H 16.5 13.5
a1 b1 3 H 17.5 14.5
a1 b1 4 G 18.5 15.5
a1 b1 5 G 21.5 18.5
9 rows selected.
Array Processing
A reader, November 02, 2011 - 4:28 am UTC
Hi Tom,
Thanks for the solution.
Could you please explain briefly what the lower part of the query is doing..ieselect pk1, pk2, serialno, ind, val1+column_value, val2+column_value
8 from data,
9 table( cast( multiset( select level-1 l from dual connect by level <=
10 case when ind = 'H' then next_val1-val1
11 else 1
12 end ) as sys.odciNumberList ) );
what is multiset and sys.odciNumberList ?
Thanks a lot
November 02, 2011 - 12:02 pm UTC
sys.odcinumberlist is just a builtin type - it is a table of number, there are types for varchar2 and dates as well.
So, it is just a collection type.
multiset takes a collection type and lets us treat it as a set - like rows.
So, when I use:
from data, TABLE( cast( multiset( query ) as sys.odicnumberlist ) )
I'm just unnesting a table (a predefined sort of join). Basically for each row from data, it will create a set of N rows in the TABLE() clause where N is either 1 (for ind <> 'H') or the number of rows that need to be made up - we'll turn that one row from data into N rows...
I love how someone says you are bashing SS.
Galen Boyer, November 02, 2011 - 11:49 am UTC
4. Stored Procs that return a resultset. In TSQL this is easy, in
Oracle this seems to require a cursor and a Package - which is like a
struct ? Anyway, I'm having to do alot more work to do something which
is trivial in Sybase - now, it may be that there is some logical
explanation for this approach in Oracle, but I haven't found one (in
the still useless migration documentation).
I remember coming from Sybase to Oracle and being frustrated by this
as well. How come I can't have a stored proc just print something
out??? Now, after coding applications that access the database,
instead of just coding in the database, I realize that a compiled
codebase has no clue of what it is getting back from a stored proc
that can return result sets or maybe could also do something. Sybase
actually puts everything that happens within a proc onto a stack, and
the calling code must walk the stack asking if anything went wrong (of
course, that's actually hard to know you need to do unless you don't
trust TSQL and decide to cause errors somewhere and then see if the
code sees them. Most of the time, your calling code will see them,
but, sometimes it does not. Then, you get worried, really test. Wow,
that error wasn't caught??? No kidding! And then you produce a bug
report to Sybase and they send you back the code to walk the stack.)
I mean, I was floored. I'm not sure what SQLServer does, but they
come from the same base platform, so it wouldn't surprise me to hear
something similar actually exists.
Array Processing
A reader, November 03, 2011 - 1:17 am UTC
Tom,
I also have similar kind of requirement but in my case
When the ind='H' i have to call a function which calculates the intermediate values where the logic is different for calulating the values(other than adding integer number of values in the above case)
How can i do it??
November 03, 2011 - 2:12 am UTC
tell us about your function and explain what you mean a bit more. What should be the input to your function for each row in the output. would it just be as simple as:
ops$tkyte%ORA11GR2> with data as
2 (
3 select pk1, pk2, serialno, ind, val1, val2,
4 lead(val1) over (order by serialno) next_val1
5 from c
6 )
7 select pk1, pk2, serialno, ind, val1+ F(X), val2+ F(X)
8 from data,
9 table( cast( multiset( select level-1 l from dual connect by level <=
10 case when ind = 'H' then next_val1-val1
11 else 1
12 end ) as sys.odciNumberList ) )
13 /
all you have to do is tell us "what is X"
Array Processing
A reader, November 03, 2011 - 4:11 am UTC
Hi Tom,
suppose i have a function as below which returns an array
create or replace function col(val1 float,next_val float) return num_array
as
in3 float;
cnt number;
temp num_array:=num_array();
begin
in3:=0;
cnt:=1;
for i in 1..4
loop
in3:=2*(next_val-val1);
temp.extend(1);
temp(cnt):=in3;
cnt:=cnt+1;
end loop;
return temp;
end;
select * from table(col(2,4));
o/p:
4
4
4
4
now when ind ='H' a call has to be made to this function and the array of values it returns need to be put after that is the values for val1 should be as below
10.5 12.5 13.5 4 4 4 4 18.5 21.5
similarly for val2.
How to go about this???
Thanks
November 03, 2011 - 5:19 am UTC
what if there are 50 rows between the two values - what then? since this function always returns 4.
Array Processing
A reader, November 03, 2011 - 5:47 am UTC
Hi Tom,
May be i am not clear in my explanation.
Here i just gave function as example.It's not my actual logic
My goal is as follows..
When ever Ind='H' in the records retrieved as per the serial number,a function or procedure should be called which will return an array of values as output.That values need to be put in the order as i mentioned above and continue with the next elements in the serial number.
meaning for ind values G val1(10.5,12.5) (11.5,12.5) will be picked straight away,next when ind='H' here my val1 and val2 will be computed based on some logic(above i gave function as an example) finally i will get val1 and val2 values which i need to put in the same order val1(4,4,4,4) in this case and continue with the remaining i.e val2(18.5 and 21.5)
The logic inside my actual scenario is little bit complex(that is why i have given simple example function above) but finally it gives intermediate values(val1,val2) when ind='H', as output and those values i need to put them in nested tables in the order as they come out.
Once i populate the nested tables with val1 and val2 values i have to perform some computations on that.
am i clear or still am missing something..
Thanks for your time.
November 03, 2011 - 5:59 am UTC
ops$tkyte%ORA11GR2> with data as
2 (
3 select pk1, pk2, serialno, ind, val1, val2,
4 lead(val1) over (order by serialno) next_val1
5 from c
6 )
7 select pk1, pk2, serialno, ind, val1+ column_value, val2+ column_value
8 from data,
9 table( your_function_here( your, parameters, to, function, here ) )
13 /
that is all - your function would return either
a) 1 element in your collection - because it is not an 'H' type
b) N elements to make up the 'gap' because it is an 'H'
Array Processing
A reader, November 03, 2011 - 6:55 am UTC
Hi Tom,
I have used above query suggested by you as follows..
with data as
(
select pk1, pk2, serialno, ind, val1, val2,
lead(val1) over (order by serialno) next_val1,lead(val2) over (order by serialno) next_val2
from c1
)
select pk1, pk2, serialno, ind, case when ind='H' then t1.column_value
else val1 end, case when ind='H' then t2.column_value
else val2 end
from data,
table(col(val1,next_val1)) t1,table(col(val2,next_val2)) t2 order by data.serialno
o/p:
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,1,G,10.5,11.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,2,G,12.5,12.5
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,4,G,18.5,15.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
a1,b1,5,G,21.5,18.5
But my o/p should be
a1,b1,1,G,10.5,11.5
a1,b1,2,G,12.5,12.5
a1,b1,3,H,13.5,10.5
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,3,H,10,10
a1,b1,4,G,18.5,15.5
a1,b1,5,G,21.5,18.5
Please suggest.
November 03, 2011 - 9:35 am UTC
suggest you give me your full reproducible test case so I can find your bug in your COL function.
tell us, does this:
table(col(val2,next_val2))
return ONE ROW when ind <> 'H'?
array processing
A reader, November 03, 2011 - 10:17 am UTC
Hi Tom,
table(col(val2,next_val2)) will be called only when ind=H and should not be called when ind<>h.
and my sample col function is
create or replace function col(val1 float,next_val float) return num_array
as
in3 float;
cnt number;
temp num_array:=num_array();
begin
in3:=0;
cnt:=1;
for i in 1..4
loop
in3:=2*(next_val-val1);
temp.extend(1);
temp(cnt):=in3;
cnt:=cnt+1;
end loop;
return temp;
end;
Thanks
November 03, 2011 - 10:38 am UTC
table(col(val2,next_val2)) will be called only when ind=H and should not be
called when ind<>h.umm, no, it will be called each and every single time. That is why I said:
that is all - your function would return either
a) 1 element in your collection - because it is not an 'H' type
b) N elements to make up the 'gap' because it is an 'H' Your table function is joined (has to be joined) to every single row in your real table. that is why when it is not 'H' - you need to return 1 row (so you a) see that row and b) see that row only once). And why when it is 'H' you need to return N rows.
I'm beginning to think you don't really know how this works - which is very very VERY dangerous. You have no way to maintain it, extend it, test it, prove that it does what you need. You might want to stop for a minute and get really familiar with the technique.
so, here is an example - this just does what my original query does because I return 0, 1, 2, 3, .... from my function when ind = "H" and I return just 0 when it isn't H
ops$tkyte%ORA11GR2> create or replace
2 function your_function_here
3 ( p_ind in varchar2,
4 p_val1 in number,
5 p_next_val1 in number
6 ) return sys.odciNumberList
7 PIPELINED
8 as
9 begin
10 if ( p_ind = 'H' )
11 then
12 for i in 1 .. p_next_val1 - p_val1
13 loop
14 pipe row( i-1 );
15 end loop;
16 else
17 pipe row( 0 );
18 end if;
19 return;
20 end;
21 /
Function created.
ops$tkyte%ORA11GR2> show errors
No errors.
ops$tkyte%ORA11GR2> pause
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> with data as
2 (
3 select pk1, pk2, serialno, ind, val1, val2,
4 lead(val1) over (order by serialno) next_val1
5 from c
6 )
7 select pk1, pk2, serialno, ind, val1+ column_value, val2+ column_value
8 from data,
9 table( your_function_here( ind, val1, next_val1 ) )
10 /
PK1 PK2 SERIALNO I VAL1+COLUMN_VALUE VAL2+COLUMN_VALUE
---------- ---------- ---------- - ----------------- -----------------
a1 b1 1 G 10.5 11.5
a1 b1 2 G 12.5 12.5
a1 b1 3 H 13.5 10.5
a1 b1 3 H 14.5 11.5
a1 b1 3 H 15.5 12.5
a1 b1 3 H 16.5 13.5
a1 b1 3 H 17.5 14.5
a1 b1 4 G 18.5 15.5
a1 b1 5 G 21.5 18.5
9 rows selected.
array processing
A reader, November 03, 2011 - 11:53 am UTC
Thanks a lot tom for your valuable time
Array Processing
A reader, November 04, 2011 - 5:19 am UTC
Hi Tom,
Bare with my ignorance..
Is 'return' statement mandatory in the pipelined table function above.
Because it's working fine without 'return' statement in the end.
Thanks.
November 07, 2011 - 9:40 am UTC
it used to be a requirement:
ops$tkyte%ORA9IR2> create or replace
2 function your_function_here
3 ( p_ind in varchar2,
4 p_val1 in number,
5 p_next_val1 in number
6 ) return sys.odciNumberList
7 PIPELINED
8 as
9 begin
10 if ( p_ind = 'H' )
11 then
12 for i in 1 .. p_next_val1 - p_val1
13 loop
14 pipe row( i-1 );
15 end loop;
16 else
17 pipe row( 0 );
18 end if;
19 end;
20 /
Function created.
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> select * from table( your_function_here( 'H', 1, 5 ) );
ERROR:
ORA-06503: PL/SQL: Function returned without value
ORA-06512: at "OPS$TKYTE.YOUR_FUNCTION_HERE", line 16
no rows selected
guess I still just do it out of habit.
It doesn't hurt.