Powered By Blogger
Showing posts with label oracle. Show all posts
Showing posts with label oracle. Show all posts

Wednesday, March 6, 2013

TNS NAMES EDITOR

Working in an environment where new Development and Test Oracle databases are created on a routine  basis means I tend to maintain my own local copy of tnsnames.ora and sqlnet.ora.

People working in other locations then tend to send you new entries in an email or even their complete tnsnames files. You can then end up trying to do a patchwork job of adding their entries into your own file.

I consider myself reasonably knowledgeable in such things and rarely have a problem but got into a tangle when I added a new entry and started getting TNS-12533: TNS:illegal ADDRESS parameters 

Fiddling around with tnsping and surfing Oracle forums led me to the conclusion that there was a typo or bracket missing somewhere. But then I read someone make a fairly valid point, which was to use the actual editors provided by Oracle!

Although I knew they existed, I rarely use them. But by using 'Net Manager' in the 'Configuration & Migration Tools' section of your Oracle Client install you can effectively manage both the sqlnet and tnsnames file. (Obviously this isn't exactly news to most Oracle Pros!).

When I initially used it to open my tnsnames file, it showed no entries in the Service Naming section which confirmed there was some sort of corruption. I ended up re-adding the entries using the editor and hey presto - all worked fine! 

Friday, March 23, 2012

Multi Select parameter from SSRS into an Oracle package

When using a SQL Server stored procedure for a dataset you can supply parameters that have 'Multi-select' property but you need some way to handle them in the SQL Server stored procedure (SP). The general approach is to unravel the comma separated string into a temp table within the  SP. Once you've done using loops and various string handling functions then you can join the resulting table to you main table to limit the rows.

In Oracle it is a bit more difficult but the principle is the same. The step by step process I came up with (please correct me if there is a simpler method...)

1. Define a Global type in your Oracle database.

This needs to be an Nested table that can hold the parameters once they have been unravelled.

CREATE TYPE GlobalKeyTableType AS TABLE OF NUMBER;

You need this because the code you are about to write will depend on this - and note it must be a global type.

2.  Write a routine to split up the keys and load them into your global table


PROCEDURE spSplit_Up_Key (
   pParameterString IN VARCHAR2, pIdTable IN OUT  GlobalKeyTableType)
AS
 
   lCommaPos          SMALLINT;
   lParameterString   VARCHAR2(2000) := pParameterString;
   lLoopCounter NUMBER:=0;
   lBreak BOOLEAN := FALSE;
   l_err_num NUMBER;
   l_err_msg VARCHAR2(100);
BEGIN

   IF (LENGTH (lParameterString) <= 0)
   THEN
      RETURN;
   END IF;

   lCommaPos := INSTR ( RTRIM (LTRIM (lParameterString)),',');

   IF lCommaPos = 0
   THEN
             
        lLoopCounter:=lLoopCounter +1;
       pIdTable(lLoopCounter) :=TO_NUMBER ( RTRIM (LTRIM (lParameterString)));
   ELSE
 
         WHILE LENGTH (lParameterString) > 1 AND NOT lBreak
         LOOP
       
            lCommaPos := INSTR ( RTRIM (LTRIM (lParameterString)),',');
             lLoopCounter:=lLoopCounter +1;
             -- Extend if bigger than 1
             IF lLoopCounter > 1 THEN
                pidTable.EXTEND;
            END IF;
            pIdTable(lLoopCounter) :=          
                    TO_NUMBER (SUBSTR (RTRIM (LTRIM (lParameterString)),1,lCommaPos - 1));
                   
            lParameterString :=
               SUBSTR (RTRIM (LTRIM (lParameterString)),
                          lCommaPos + 1,
                          LENGTH (RTRIM (LTRIM (lParameterString))));
            lCommaPos := INSTR ( RTRIM (LTRIM (lParameterString)),',');

            IF lCommaPos = 0
            THEN
           
             lLoopCounter:=lLoopCounter +1;
             -- Extend if bigger than 1
             IF lLoopCounter > 1 THEN
                pidTable.EXTEND;
            END IF;
       
                  pIdTable(lLoopCounter) :=  TO_NUMBER (RTRIM (LTRIM (lParameterString)));

                  lBREAK:=TRUE;
               END IF;
            END LOOP;
           END IF;
         
           EXCEPTION
     WHEN NO_DATA_FOUND THEN
       NULL;
     WHEN OTHERS THEN
       l_err_num := SQLCODE;
      l_err_msg := SUBSTR(SQLERRM, 1, 100);
     
       DBMS_OUTPUT.put_line( TO_CHAR(L_err_num) || ' : ' || l_err_msg);
       RAISE;
     
     
           END spSplit_Up_Key;

This SP is best stored centrally in its own package accessible by various other routines. I actually have another one for splitting up VARCHARs but the principle is the same.

3. Call the SP and use the returned table

In you main SP you'll need to call the spSplit_Up_Key and capture the returned NESTED TABLE.

Note you'll have to declare (and initialise) the table in your calling routine - here is an example of where I've used it to capture a list of teams and am now using it in the query.


AND teamid  IN
 (  select a.column_value  val
    from THE ( select cast( lTeamKeyTable as GlobalKeyTableType )
                               from dual ) a)

You may need to define more than 1 depending on how many multi values parameters you are passing in.

4. Hook up Reporting services to call the Oracle SP


Refer to my previous post for this but remember when passing the parameter to pass the joined string using

JOIN(pTeams,",")

Conclusions...
This took me longer than it should have done! There are several small gotchas which I haven't included here as would make the post to long but this is enough to get it working.

Thursday, March 22, 2012

Reporting Services calling an Oracle Stored Procedure

Most of the recent SSRS work I have done has been off a SQL Server datasource. And, for anything other than the simplest queries you'd write a Stored Procedure (SP) in the database which returned the rows you want. This is achieved nicely in T-SQL as you can do whatever you want in the body of the SP e.g set flags, create temporary tables, build objects and then end your SP by just writing a SELECT statement. The rows returned get picked up by the SSRS Report in the datasource and once you've mapped your fields then you are away.

In Oracle I didn't find it as simple. Maybe a combination of letting my PLSQL get rusty but also I think that PLSQL is just not geared up to do this in as simple a way.

In any case, I did get it working, and once you know how it is straightforward! The process is to create a Procedure in your Oracle database whose last parameter is and OUT parameter of type SYS_REF_CURSOR. Here is a short example of one I wrote:

 PROCEDURE spPickOrderStatus(pOrderStatuses OUT SYS_REFCURSOR) IS
  BEGIN


   OPEN pOrderStatuses
   FOR
   SELECT
      oid.order_ind, 
      order_ind_desc
   FROM
      mm_order_indicators_dim;


   EXCEPTION
     WHEN OTHERS THEN
       -- Consider logging the error and then re-raise
       RAISE;
  END;


Change the datasource in you report to be Oracle and choose the query type to be "Stored Procedure". The field should be mapped as smoothly as with a SQL Server datasource.




Tuesday, March 20, 2012

Case Sensitivity

I'm sure this can be changed by your friendly SQL Server DBA but worth noting that, by default, SQL Server databases are case insensitive whereas with Oracle you do need to distinguish between your P's and your p's!

For example when searching for the word 'Tower', the following line

SELECT *
FROM MyTable
WHERE name LIKE '%ToWeR%'

will bring back the row in SQL Server but NOT in Oracle.

Saturday, October 16, 2010

Analysis Services for Federated BI

Having struggled on my first attempt I tried a second time to build an AS cube over Oracle and SQL server data and get it all to knit together. There are a few gotchas but here is the basic step by step guide:
1. Create a SQL server data source
2. Create an Oracle Data Source (I used Oracle OLEDB)
3. Create a DSV for the SQL server objects
4. Create a seperate DSV for the Oracle objects

* Note that putting both sets of objects in a single DSV seems to create an issue where the cube tried to access the Oracle objects through the SQL server database using a linked server - slightly defeating the overall purpose..

5. Create 2 cubes - one from each data source and get your dimensions how you'd like them
6. Identify an Oracle dimension that would be useful, and will join, to a measure group in the SQL server cube
7. Open up the SQL server cube and go to 'dimension usage'
8. Right click to add a linked objects and choose the Oracle cube
9. A linked measure group will appear and you should now be able to join the SQL server measure group to the Oracle dimension

* Note that this does not seem to work the other way round (ie adding the SQL server measures group as a linked measure group to the Oracle cube)
* Also note you may battle with type when joining but change types in DSV named queries if you have to

10. You may want to input any missing relationships between the cubes as 'many to many' relationships
11. Process the cube and query both measures groups using either dimensions

Oracle 10g Express Edition

Have been installing Oracle 10g server and client on my laptop so I can play around with developing an Analysis Services Cube that can join SQL Server and Oracle tables together.

All going well, though hit a problem that BIDS couldn't connect to the XE database through an Oracle connector or Oracle OLEDB. After a good while googling I gave up but then had a thought. I found the registry setting for the Oracle XE Client and create a TNS_ADMIN entry that pointed to the server install TNSNAMES directory. I'd installed both server and client on my D drive so this worked fine.