What’s So Great About PL/SQL By Paul Hunter Thanks to our Gold Sponsors
Overview Introductions: Topics: Paul Hunter paul.hunter@NightOwlSystems.com Topics: Translating to Oracle Procedures & Functions Package / Package Body PL/SQL Native Function Highlights
A Little About Me I’ve been a developer for 20+ years and a SQL developer for 12 of those years I’m a Certified Scrum Master NTSSUG - NorthTexas.SQLPass.org DFW Scrum - www.DFWScrum.com Dallas ASP.NET User Group www.DallasASP.net Application development & design w/SQL & .NET I prefer Agile/SCRUM over waterfall methods Follow me on Twitter: @SqlNightOwl
Translating to Oracle Oracle & SQL Server are different, but the same. Many of the concepts map over very nicely while others need a little more work. SQL Server Oracle Instance Database Schema Page Block FileGroup TableSpace SQLCMD SQL*PLUS
More Translations rownum – this is similar to the top operator sysdate – returns the system date/time down to the second dual – This is not a function. This is an internal table containing a single row. There are many uses for this internal table. One common use is equivalent to the Numbers/Tally table in SQL server. Pick your favorite numbers/tally table method in these types of cases. sequence – delve into currval nextval desc[ribe] – this is similar to sp_help but only returns column name, null-ability and data type. Still, it’s handy. connect by – This is a pretty cool piece of functionality unique to Oracle. I’ve seen this used in recursive CTEs to help control the hierarchy. In these cases, it limits the result set to rows meeting the criteria of the connect by statement. Similar functionality can be achieved through use of Joins and the Where clause.
Working with Oracle I like using linked servers because you can then query Oracle using one of two methods: Direct Query: SELECT * FROM LSN..SCHEMA.TABLE_OR_VIEW OpenQuery: SELECT * FROM OPENQUERY(LSN, 'SELECT * FROM TABLE_OR_VIEW')
Procedures & Functions There are many similarities between a SQL Server stored procedure and an Oracle procedure; however there are some significant differences: You must declare the parameter direction (in/out/inout) The parameters must be enclosed in parentheses (ever if there are no parameters) You cannot return a recordset from an Oracle procedure. Insert, update & delete are the only supported actions; however you can return a single record thru output parameters or in RowType variable. PL/SQL uses unbound blocks
Sample Block Header CREATE OR REPLACE PROCEDURE procedure_name ( parameter_name direction datatype [:= default_value] [, parameterX direction datatype [:= default_value]] ) IS -- but you can also use AS Declaration Section DECLARE variable_name datatype [:= initial value]; BEGIN Execution Section select some_value into some_variable from some_table where column_name = parameter_name; Now go and do something interesting... EXCEPTION Exception Section when NO_DATA_FOUND then null; when other rollback work; END;
Miscellaneous Stuff %type / %rowtype – this is REALLY COOL. You can declare variables based on a specific column’s data type or the type of the entire row. If you’re using a linked server, you can execute the procedure by creating an anonymous PL/SQL block: declare @cmd varchar(50) set @cmd = 'begin procedure_name( parameter_value [, etc.] ); end;'; exec (@cmd) at LSN;
Package / Package Body This is similar in concept to an interface class and the implementation of the interface in another class. The Package specifies the declaration of the public method “signature” The Package Body contains the procedures and functions to implement the Package interface The Package Body may contain many more procedures and functions than are defined in the Package. There is a 1-to-1 mapping between a Package and Package Body
PL/SQL Functions Aggregates Strings Most of these are named and behave the same as their SQL Server counterpart. Strings || – concatenation in PL/SQL initcap() – no comparable function applies to the first letter of each word in a string. lpad() / rpad() – allow you to pad a string with another string. If no pad string is provided then a blank space is used.
Strings (continued) substr() – In SQL, this translates to substring. Easy enough right? There is one more difference between the two than just the name. The parameters are ordered differently in substr() than they are in substring(). Pay careful attention to your parameter sequence when converting this function from Oracle to SQL Server. instr() – This one is less obvious. I have used PatIndex() and CharIndex() for this one – depends on needed functionality. If you understand that instr is searching for a value within a string – it makes it a little easier to understand. Also knowing that PatIndex searches for “Patterns” and CharIndex() searches for a character is helpful. If you need to supply the optional parameter used by instr(), then you should use CharIndex. Though not entirely the same – similar functionality is available in SQL for the instr() function.
Dates add_months() – adds X number of months to the date provided. If the original date is the last day of the month then the date returned will always be the last day, otherwise the day will remain unchanged. Negative numbers can be moved to find prior dates. last_day() – returns the last day of the month for the date provided. months_between() – returns the number of months between the two dates. Returns an integer if the two dates are the same day of the month otherwise it’s a decimal value. next_day() – returns the next occurrence of a specific weekday
Miscellaneous Functions greatest() / least() – will take the max/min value in the list of values provided. Kind of an aggregate without having to us a group by. decode() – similar to inline if or case statement (max parameters 255). Sample: decode(some_column, null, ‘no where’, ‘TX’, ‘Texas’, ‘OK’, ‘Oklahoma’, ’who cares’) trunc() – converts a date or number to an “integer” format (removes time portion of dates or no decimal places). This is achieved through different means in SQL. Two common methods are cast(), convert() and/or floor(). nlv() – functionally equivalent to isnull()