- Community Pick
- Experts Exchange Approved
- Editor's Choice
- 0
Introduction
But with the issue that the list should be a parameter at some point (either in the sql procedure itself, or the programming language that calls the sql). And to take the MS SQL Server syntax as example, the following does not return an error, but simply does not work:
It will return the one matching employee record if you pass 1 single ssn value to the procedure.
As soon as you pass several items in the list, you will get:
0 records returned.
The explanation is this: for the SQL engine, @ssn_list is 1 single (string/varchar) value, while for the human reader, there is indeed clearly the list. We will see in the next steps the different solutions for this.
Note: in all the examples, we will consider the procedure is called with the list with comma as separator, no spaces, no (additional) quotes inside the list:
- 1
Quick and Dirty: Dynamic SQL
For MSSQL, it's this easy:
In short, you build the sql "on-the-fly", and execute it. There are 2 issues with this:
- SQL injection (in general: READ IT): Wikipedia. I won't go into the details, but take it as a very serious
- Security: in MS SQL Server, the dynamic sql will run under the permissions of the caller of the stored procedure, and not of the owner of the stored procedure.
In Oracle, we cannot return a recordset like in MS SQL Server or MySQL, you need to return a ref cursor, and the calling application has to loop somehow through the cursor.
There is an alternative, for Oracle, using the PIPELINED function method shown later, though, but you might want to explore that yourself
So, the corresponding code would read:
As from MySQL 5.x, it's also possible, but a bit more complicated. Here as to be run using the mysql command line:
Due to the issues noted above, please do NOT use that kind of syntax, but read further!
- 2
Inefficient Method
Another method you will find is the a syntax using LIKE to find a match in the string. This trick can sometimes be very useful, but used alone, the big issue with this is performance: it will be unable to use any index on the ssn field.
The explanation of how it works is obvious once you replace, for visualization, the variable and the column value:
Hint: if the field ssn was of numerical data type, you would need to write cast(ssn as varchar(100)), for example.
As usual, the translation for MySQL:
You might find the built-in FIND_IN_SET function from MySQL a very tempting alternative:
http://dev.mysql.com/doc/
To finish, the Oracle version (I hope you don't get lost in the quotes):
- 3
Parse the list into a set
So, we need to get a true list from that string. In my MS SQL Servers, I have this function implemented:
and the function is used like this:
I will not discuss (here) on how efficient my function is, as that is out of the scope of this article.
note: the row_num field returned by my function is to allow ordering of the result set by the order in which the items are in the list, if that is needed, using the join syntax:
In MySQL, there is no alternative, unfortunately, as:
- user-defined functions can only return single values
- procedures cannot be used (like in most other databases) directly inside a query
If you find differently, please post, and I will update the article accordingly (with credits).
In Oracle, I implemented a similar function than in SQL Server, using the PIPELINED technique. We will need a preparation, though:
Now, we can create our function:
And the usage would be like this:
You now have a method to do this without dynamic sql, though still nice and easy-to-read code, and possibly using a index on ssn field. You will see that you can reuse that function quite often in your developments.
- 4
Parse using XML features
Again, we must leave MySQL out of the picture, as it does not (yet) have the XML features required.
MySQl 5.1 does have some XML support, but there is no method to get a set from the xml:
http://dev.mysql.com/doc/
With MS SQL Server 2005 or higher, we could delegate the parsing to XML. You can choose the tag names as you wish (XML is case sensitive!), I choose the shortest possible length; the <t> stands for table, while <r> stands for row.
The usage is the same as for my other version. Of course, this function could have a brother that accepts the xml directly, or you could use that directly in your procedure, avoiding the additional function call.
For SQL 2000, you could use the OpenXML function to implement the same.
As from Oracle 9i, we can implement the same XML parsing:
For both MS SQL Server and Oracle codes, not being used to XML in general, it took me a couple of hours to get both working correctly. Hence, don't be discouraged if you don't understand the syntax right away.
- 5
Even other alternatives
I got reference of this page: http://vyaskn.tripod.com/
With MS SQL Server, we could explore even another method, using CLR (.net) stored procedures.
However, as with the XML table, for the simple task given here, the overhead will just be not worth the effort.
For Oracle, the corresponding feature would be java stored procedures/functions.
I do agree that T-SQL and PL/SQL are not necessarily more efficient to parse the CSV/XML. However, for the task given, it is efficient enough rather than call for "outside" methods.
- 6
IN and it's alternatives
For sake of simplicity, I sticked with the IN (subselect) in steps 3 and 4. Of course, for matters of performance, you could first insert the results of the parsing code into a intermediate (temp) table, and then use either of the 3 syntax:
Notes:
- the IN() syntax will require that the subquery does NOT return a NULL value.
- the JOIN syntax will require the temp table has no duplicates
- in MS SQL Server, you can use either a #temp table, or a @table variable
You could also bypass the (temp) table, and join directly to the function, as I showed already above:
The JOIN with the function also works in Oracle.
- 7
Conclusions and Warnings
*WARNING*
Though tempting and quick to implement, you should think at least twice before using one of the two first suggestions.
*XML Overhead*
The XML method is interesting to know, but the XML overhead (more data, more parsing) makes this method (likely) less efficient. Though, for an UPDATE of several rows at once, this can be a very powerful method. See concrete example in MS SQL here (requires registration):
http://www.sqlservercentra
In regards to the overhead, just do the math: consider you want to pass X items with N characters length.
With the CSV format, you will pass exactly (N*X) + (X-1), in short 1/Nth overhead.
For XML, you will need more: (N*X) + (X*7) + 7, in other words, over 7/Nth overhead.
This will negatively impact, with high load, network bandwidth to and from the server, as well as CPU and Memory usage on the server.
*LIMITS*
It is important that you know the string size limits of your database/version.
MS SQL Server 7 and 2000 VARCHAR == 8000
MS SQL Server 2005+ both XML and VARCHAR(MAX) == 2GB
MySQL's VARCHAR size depends on the version:
up to MySQL 5.0.2 == 255
MySQL 5.0.3 or higher == 64K
Note: if you need more data for your list in MySQL, you might use a MEDIUMTEXT or LONGTEXT data type
Oracle's VARCHAR2 == 4000
Note: if you need more data for your list in Oracle, you will need a CLOB data type
I hope you find the article helpful for your current or future developments in any of the databases you are working with.
If you find/know some other method to implement the above, also in other databases, you are welcome to post that information here.
- "" title="References"]
MS SQL Server
Create Stored Procedure:
SQL 2000: http://msdn.microsoft.com/
SQL 2005: http://msdn.microsoft.com/
SQL 2008: http://msdn.microsoft.com/
MySQL
Create Stored Procedure syntax:
http://dev.mysql.com/doc/r
sql prepare syntax:
http://dev.mysql.com/doc/r
Oracle
Create Stored Procedure syntax:
www.techonthenet.com/oracl
Implement pipelined functions:
http://www.akadia.com/serv
Using xml table extractions:
http://stanford.edu/dept/i
http://download.oracle.com
by: angelIII on 2009-09-23 at 12:50:54ID: 3710
a million thanks for aikimark, revisor for this article, staying with me until te article was publishable!
hopefully you will find your valuable "nugget" here.
angel eyes