This page from SQL Server 2008 BOL, talks about CLR Stored Procedures and has a section labelled, "Table-Valued Parameters", which talks about how they can be advantageous. That's great - I'd love to use TVPs in my CLR procs, but unfortunately this seems to be the only reference in the universe to such a possibility, and the section doesn't describe what the syntax would be (nor does the further information linked at the end of the paragraph)
Sure, I can easily find descriptions of how to use TVPs from T-SQL procs, or how to do CLR procs in general. But writing a CLR proc that takes a TVP? Nothing. This is all highly unusal since the passing of multi-row data to a stored proc is a popular problem.
This leads me to wonder if the presence of the section on that page is an error. Somebody please tell me it's not and point me to more info/ examples.
[EDIT]
I was about to post this to one of the MS forums too when I came across this, which seems to be the final nail in the coffin. Looks like it can't be done.
I can find a lot more references. However, these are all for passing table-valued parameters to TSQL procedures, so that's of little use.
However, I've come to the conclusion that it's impossible. First, there is the list of mappings between CLR and SQL types. For table types there is no mapping, so the following does not work, for example:
[SqlProcedure]
public static void StoredProcedure(DataTable tvp, out int sum)
{
return 42;
}
and then
CREATE TYPE MyTableType AS TABLE
(
Id INT NOT NULL PRIMARY KEY,
[Count] INT NOT NULL
)
GO
CREATE ASSEMBLY ClrTest FROM '<somePath>'
GO
CREATE PROCEDURE ClrTest
AS EXTERNAL NAME ClrTest.StoredProcedures.StoredProcedure
GO
Whatever type you try (DataTable, DbDataReader, IEnumerable), the CREATE PROCEDURE call keeps generating an error 6552: CREATE PROCEDURE for "ClrTest" failed because T-SQL and CLR types for parameter "#tvp" do not match.
Second, the documentation on the page you linked to says: A user-defined table type cannot be passed as a table-valued parameter to, or be returned from, a managed stored procedure or function executing in the SQL Server process.
I can not seem to find anywhere how to create a user defined table type in C#, but this also seems to be a dead end.
Maybe you can ask your question somewhere on a Microsoft forum. It's still odd that they mention table-valued parameters on the CLR sproc page but never explain how to implement this. If you find any solution, I'd like to know.
You can use a temporary table created and populated before you call the procedure and read the table inside the clr procedure.
The solution is to serialize your tabular data into a Json-formatted string then pass the string into your CLR proc. Within your clr proc or function you would parse the json to an IEnumerable, list, or tabular object. You may then work with the data as you would any other type of tabular data.
I have written some utilities capable of serializing any sql table into a Json formatted string. I would be happy to share them with anyone providing their e-mail address. Phil Factor has written a nice T-SQL Json parser he called parseJson. I have adapted his solution to the clr which performs much faster. Both accept a Json formatted string and produce a table from the string. I also have a variety of Json utilities I employ with both T-SQL and the CLR capable of serializing, parsing, inserting, deleting, and updating Json formatted strings stored in sql columns.
If you use C# (as opposed to VB, which lacks custom iterators) you can write ADO.NET code to invoke ExecuteNonQuery() and run a stored procedure with a SqlDbType.Structured parameter (i.e., a TVP).
The collection passed as the value of the TVP must implement IEnumerable<SqlDataRecord>. Each time this IEnumerable's yield return is executed, a SqlDataRecord “row” is pipelined to the "table" parameter.
See this article for details.
Whilst it looks like passing tables directly to CLR procedures is currently impossible, I got a result, albeit sub optimal by:
defining a TSQL table valued UDT FooTable
defining a TSQL function which takes FooTable as a param and returns XML using FOR XML EXPLICIT
passing the resultant XML to the CLR function/procedure instead of the table itself
Not ideal, but it gets a bit closer.
Related
Yes, of course, I know, there are many different generators created on Javascipt, php, etc. and even applications and web-services that allow generating sql.
But I’d like to have sql functions library which can be used during generating data right away from MySQL script and stored procedures.
Now I'm creating my own helper functions (and it’s quite tedious) that work roughly like bellow:
(fl_* - are functions that return fake data of corresponding type and features.)
-- create a fake user:
call sp_user_add(fl_login(), fl_email(), fl_gender(), #user_id);
-- add a fake post:
call sp_post_add(#user_id, fl_title(true, 1, 10), fl_body(true, 3, 20), #post_id);
You need to know mysql random data generator stored procedure.
See http://www.generatedata.com/. Here you can select the SQL-Tab and select the number of rows you want to get created. The result is a SQL-script you can copy-paste. I found this very handy...
I have a view with one column containing domain\useraccount as an nvarchar(100). I need to convert the value in this column from domain\useraccount to Last, First Middle. I have successfully created a linked server (ADSI), and can resolve a hard-coded account name to an actual name via an OpenQuery call.
However, making the OpenQuery call from within the view is proving impossible. I've tried the following options:
Use string substitution/concatenation in the OpenQuery call.
Create a function to wrap the OpenQuery call, and call that function from the view.
Neither of the above options works. #1 fails because OpenQuery only accepts a pre-formed string as an argument and it isn't possible to create one (as far as I know) in a view. #2 fails because, based on the error message I got when I tried, functions called from views can't themselves contain calls to EXEC(string). #2 is actually a variation on the official workaround per this KB article:
http://support.microsoft.com/kb/314520
Can anyone shed some light on this? It almost seems like there's no way to make parameterized OpenQuery calls in a view.
Thanks!
There are a lot of examples over the net which describe how to call a stored procedure using Hibernate, however, when using Spring, the picture changes a bit.
I have a stored procedure in MySQL which I want to call:
in SQL I need to write the following:
CALL inrange(32.342324,32.234234);
It returns a row with the following: `{INT},{INT},{FLOAT}`
With Spring, I use the HibernateTemplate way of executing hibernate operations, I know that some of you won't like it, but this is the how the project was when I started, and I'm not so eager changing it, maybe in the future...
Currently, I have the following code in Java, which tries to call the procedure:
List<Object[]> resultset = hibernateTemplate
.findByNamedQuery("inrange",
person.getAddress().getLatitude(),
person.getAddress().getLongitude());
When I run it, I get the following Hibernate exception:
org.springframework.orm.hibernate3.HibernateSystemException:
Named query not known: inrange;
I figured that this is happening duo the fact that I didn't declare the stored procedure in hibernate.
My question is:
how do I declare it ?
Is there a special way of declaring it in the Spring's application context file ?
You can call native sql queries within hibernate.
Look at this link:
http://www.mkyong.com/hibernate/how-to-call-store-procedure-in-hibernate/
Btw if you want to call stored procedures you could simply use a Spring JdbcTemplate.
Notice that an hibernate extension can fit to your needs:
http://www.hibernatespatial.org/
You're confusing Hibernate's named queries with MySQL's stored procedures.
If you want to call the MySQL stored proc, there is no benefit to doing so through Hibernate's API. I recommend you use Spring's JdbcTemplate to perform the query.
If you absolutely must use Hibernate, something like this should work:
SQLQuery query = hibernateTemplate.getCurrentSession()
.createSQLQuery("SELECT inrange(:latitude, :longitude)";
query.setDouble("latitude", ...);
query.setDouble("longitude", ...);
List<Object[]> result = query.list(); // requires casting for generics
You need to add the named query to your hibernate mapping file.
Can you share your hibernate mapping file? You can find some samples here.
Along with the previous link you can go through this also.
It will be easier if you can share the POJO, hibernate mapping and the procedure you are using.
This blog will be of help for you. I hope you will not have any problem with using the getHibernateTemplate().execute(HibernateCallback) method.
You can use JPA as Spring supports it either in Core or Spring Data.
Calling the stored procedure can be done using the StoredProcedureQuery as follows:
StoredProcedureQuery query = entityManager
.createStoredProcedureQuery("count_comments")
.registerStoredProcedureParameter(
"postId", Long.class, ParameterMode.IN)
.registerStoredProcedureParameter(
"commentCount", Long.class, ParameterMode.OUT)
.setParameter("postId", 1L);
query.execute();
Long commentCount = (Long) query
.getOutputParameterValue("commentCount");
I want to create a stored procedure to do some combined keyword search using CONTAINS,something like below:
SELECT theContent
FROM FtsTest
WHERE CONTAINS
(theContent,
' FORMSOF (INFLECTIONAL, keyword1) AND FORMSOF (INFLECTIONAL, keyword2)');
and he number of keywords may vary, so I tried to pass the whole 'FORMSOF... AND FORMSOF.....'clause as a parameter,declaring the parameter as nvarchar(max),but it won't let me do it,saying The argument type "nvarchar(max)" is invalid for argument 2 of "CONTAINS".
So, is there any way to make it work with the sp?
Thanks!
Just declare argument 2 of contains as nvarchar(4000) instead of nvarchar(max) and it will work.
See the difference here: https://msdn.microsoft.com/en-us/library/ms186939.aspx
2 GB is a bit too much for the search expression.
this seems stupid,but using nvarchar(500) instead of nvarchar(max), Sql Server cheerfully accepts it and works just fine.
Still trying to gain some insight on sp_executesql,thanks.
You could build it dynamically and pass in the keywords as parameters. Executing with sp_executesql allows you to take advantage of the query plan cache, as described in the answers to this question:
Alternative to executing dynamic sql
You may need to watch out for this issue, though, that relates to parameter sniffing and full text queries:
http://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=510118
Recently we turned a set of complicate C# based scheduling logic into SQL CLR stored procedure (running in SQL Server 2005). We believed that our code is a great SQL CLR candidate because:
The logic involves tons of data from sQL Server.
The logic is complicate and hard to be done using TSQL
There is no threading or sychronization or accessing resources from outside of the sandbox.
The result of our sp is pretty good so far. However, since the output of our logic is in form of several tables of data, we can't just return a single rowset as the result of the sp. Instead, in our code we have a lot of "INSERT INTO ...." statements in foreach loops in order to save each record from C# generic collection into SQL tables. During code review, someone raised concern about whether the inline SQL INSERT approach within the SQL CLR can cause perforamnce problem, and wonder if there's other better way to dump data out (from our C# generic collections).
So, any suggestion?
I ran across this while working on an SQLite project a few months back and found it enlightening. I think it might be what you're looking for.
...
Fastest universal way to insert data
using standard ADO.NET constructs
Now that the slow stuff is out of the
way, lets talk about some hardcore
bulk loading. Aside from SqlBulkCopy
and specialized constructs involving
ISAM or custom bulk insert classes
from other providers, there is simply
no beating the raw power of
ExecuteNonQuery() on a parameterized
INSERT statement. I will demonstrate:
internal static void FastInsertMany(DbConnection cnn)
{
using (DbTransaction dbTrans = cnn.BeginTransaction())
{
using (DbCommand cmd = cnn.CreateCommand())
{
cmd.CommandText = "INSERT INTO TestCase(MyValue) VALUES(?)";
DbParameter Field1 = cmd.CreateParameter();
cmd.Parameters.Add(Field1);
for (int n = 0; n < 100000; n++)
{
Field1.Value = n + 100000;
cmd.ExecuteNonQuery();
}
}
dbTrans.Commit();
}
}
You could return a table with 2 columns (COLLECTION_NAME nvarchar(max), CONTENT xml) filled with as many rows as internal collections you have. CONTENT will be an XML representation of the data in the collection.
Then you can use the XML features of SQL 2005/2008 to parse each collection's XML into tables, and perform your INSERT INTO's or MERGE statements on the whole table.
That should be faster than individual INSERTS inside your C# code.