Thursday, September 29, 2005

Never do in SQL what you can do in PL/SQL

Back when I first started out as a trainee Forms developer, one of my colleagues had the bright idea of implementing some "CONNECT BY PRIOR" logic step by step, in Forms. The trigger would add a new blank record to the block, then retrieve the next row into it with SELECT INTO, then loop around until there were no more rows to process or Hell froze over. Perhaps unsurprisingly, it was a close thing.

I mentioned to Scott Swank that we were always on the lookout for material, and he sent me the following code that he'd come across (after editing it for brevity and anonymity), and somehow it reminded me of that old Forms trigger. This pattern is repeated ten times throughout the code, checking for various child attributes by (how else?) looping through all the records one by one until the desired attribute is found not to be true (and if something is not untrue then it must be true, right?)

PROCEDURE has_an_attribute
    ( x IN VARCHAR2, resultout OUT VARCHAR2 )
IS
    l_parent_id   VARCHAR2 (30);

    CURSOR c_child
    IS
        SELECT an_attribute
        FROM   child_table
        WHERE  parent_id = l_parent_id;
BEGIN
    l_parent_id := some_function(x);
    resultout := 'COMPLETE:Y';

    FOR v_child IN c_child
    LOOP
        IF v_child.an_attribute = 'N'
        THEN
            resultout := 'COMPLETE:N';
            EXIT;
        END IF;
    END LOOP;
END;

Wednesday, September 28, 2005

Check List

( ) Written dodgy concatenated embedded sql?
( ) Wrapped it in shell script?
( ) Littered it with literals?
( ) Included some random control characters?
( ) Released it without checking it works?

( ) Remembered to add the sarcastic comment questioning someone else's ability?
# formatting had to be included in select statement
# could this suggest the database could use some normalisation?
strqry="select invoice_line_items.product_code||"
strqry=$strqry"invoice_line_items.customer_type||"
strqry=$strqry"invoice_line_items.product_sku||\n^D"
strqry=$strqry"substr(expiry_date,3,4)||"
strqry=$strqry"to_char(trunc(instant_cost/10000),'FMX')||"
strqry=$strqry"to_char(mod(instant_cost,10000),'FM0999')||"
strqry=$strqry"contract_type"
strqry=$strqry"from invoice_line_items, retail_calendar, customer_contract,"
strqry=$strqry"product_domain"
strqry=$strqry"where last_retail_day >= retail_calendar.retail_day"
strqry=$strqry"and first_retail_day <= retail_calendar.retail_day"
strqry=$strqry"and retail_calendar.day = $day"
strqry=$strqry"and retail_calendar.month = $month"
strqry=$strqry"and retail_calendar.year = $year"
strqry=$strqry"and invoice_line_items.line_code='$flag'"
strqry=$strqry"and customer_contract.line_code='$flag'"
strqry=$strqry"and invoice_line_items.product_code=customer_contract.product_code"
strqry=$strqry"and invoice_line_items.customer_type="
strqry=$strqry"      customer_contract.customer_type"
strqry=$strqry"and invoice_line_items.product_sku="
strqry=$strqry"      customer_contract.product_sku"
if [ $host_id != "-1" ]; then
        strqry=$strqry" and product_domain.host_id = $host_id"
fi
strqry=$strqry"and invoice_line_items.product_code=product_domain.product_code"
strqry=$strqry"and invoice_line_items.customer_type="
strqry=$strqry"      product_domain.customer_type"
strqry=$strqry"and invoice_line_items.product_sku="
strqry=$strqry"      product_domain.product_sku;"

Thursday, September 22, 2005

Fun with String

It seems that my predecessor needed to convert a row of five columns into a column with five rows. Simple enough, you might think, once you realise that you can use a handy collection type in a TABLE() expression. But hey, why stop there when there is a much, much harder way involving a string-to-table function and a self-join on three columns? ...that aren't quite unique... (Table and column names changed to protect the guilty)
SELECT ...
FROM   huge_table t
     , TABLE ( SELECT utils.string_to_table
                      ( t2.col1 || ',' || t2.col2 || ',' ||
                        t2.col3 || ',' || t2.col4 || ',' || t2.col5)
               FROM   huge_table t2
               WHERE  t2.switch_id = t.switch_id
               AND    t2.switch_ctn = t.switch_ctn
               AND    t2.phone_prefix = t.phone_prefix
               AND    ROWNUM < 2 )
Now if that isn't half ample in the WHERE, I don't know what is.

Thursday, September 15, 2005

Joins explained

Remember to print out the following definitions and keep them by your desk in case you forget what a complex right inner join is (from the article "Database design for platform independence", TechRepublic 2002):

Don't use joins
Joins become a problem with Oracle and SQL Server DBMSs because the two systems have fundamentally different approaches to the concept. Basically, joins don’t always work the same on every DBMS, and you can end up with unexpected result sets. Before we talk about the differences and how to get around them, you should understand the basic types of join clauses:
  • Join
    Joins are powerful SQL commands for creating tables from data that is retrieved from multiple sources.
  • Equi-Join
    Equi-Joins are formed by retrieving all the data from two separate sources and combining it into one, large table.
  • Inner/Outer Join
    Inner Joins are joined on the inner columns of two tables. Outer Joins are joined on the outer columns of two tables.
  • Left/Right Join
    Left Joins are joined on the left columns of two tables. Right Joins are joined on the right columns of two tables.
  • Compound/Complex Joins
    There are also other kinds of joins—left/inner, left/outer, right/inner, and right/outer.
The important thing to remember about joins is to not use them if you want your application to work well with different database servers.

I love the way that it's exactly the kind of thing you would make up, if you were 12 and had absolutely no idea how to answer a homework question.

While I'm at it I can't help quoting a bit more, this time about the well-known ADD command:

ANSI SQL: CREATE, DROP, ADD, UPDATE, DELETE, INSERT, SELECT
As a rule, the only commands you should use are:

  • CREATE and DROP for Data Definition Language (DDL).
  • ADD, UPDATE, DELETE and INSERT for Data Manipulation Language (DML).
  • SELECT for data retrieval.

Friday, September 09, 2005

Twirled Half Ample in the WHERE

It is of course completely unfair to post this message by someone who clearly does not speak English. Actually you have to admire his valiant effort to describe a problem with dynamic ref cursors in a foreign language, through what must be the world's most eccentric translation software, or possibly using only a rather old dictionary. (Credit also goes to Art Metzer who actually provided a solution.) But it remains our all-time favourite Oracle forum post, so here it is:
Hi!!

I am with one doubts, I mounted one procedure that to need to return a cursor.

The STRING SQL is must be twirled half ample in the "WHERE".

For that haven't to make varios ifs, would like to know if is possible to create one parameter that it comes with where and to place in the routine to twirl, I tried to make this but not gave certain.

It below follows:

OPEN RCURSOR FOR SELECT * FROM TABELA1 WHERE CAMPO1 < 10 || VARIAVEL1

In var(VARIAVEL1) it would be:

'AND CAMPO2 = 3 AND CAMPO3 > = 25'

For example, this would be possible?

Or I will have exactly that to mount one 'IF' giant for to treat all the routine.

Tks.

See www.orafaq.com/forum/mv/msg/4467/12407/0 for the original post.

Saturday, September 03, 2005

If at first you don't succeed

Just came across this in a rather large query I have to fix:
NVL(di_core.di_tools.area_code_translate(v_switch_id,d.dncode),
    di_core.di_tools.area_code_translate(v_switch_id,d.dncode))

Friday, September 02, 2005

Mail it

I recently received the following request on a web forum:
Hello,

Please let me know how can we send an oracle database via e-mail to other people. Please reply ASAP as it is very urgent. The project is struck because of this.

Thanks in advance
Hmm. I replied asking for some descripton of the business requirement, and mentioned exp/imp utilities, .dmp files being typically smaller than an entire database, possibly XML, etc. Back came the reply:
Thank you sir for your inputs.

Actually I am from core electronics, VLSI background.

We need to configure a database (it contains all the information of components that can be used).

I have worked with Access database(which we can send and receive by zipping and sending).

Now the problem is that the person1 who is else where in globe has to send me the oracle database. Now we dont know how do we do that.We dont even have those passwords or anything... I just have no clue wht it is like .. wht options.. nothing

Now could you please tell me how can we send the database

Thanks
Oh dear. What is the file extension of the files they are sending you? I asked. Do you have an Oracle license? I must admit I had to look up VLSI ("Very Large Systems Integration", of course). And then when all hope seemed lost:
got my way

I asked the person having database to put it on FTP...

i would then be able to get that whole folder and hence the database...

Thanks for your time
Problem solved I think.