獲取存儲過程返回值的幾種方式 - yiyishuitian - 博客園.html(https://www.cnblogs.com/BinBinGo/p/6243670.html?utm_source=itdadao&utm_medium=referral)
1、
1 正常存儲過程帶RETURN(只能返回整型)
CREATE PROCEDURE p_test1 AS DECLARE @int int SET @int = 102400; RETURN @int;--這里只能返回整型 --執行 DECLARE @p1return INT --聲明一個變量 EXECUTE @p1return= p_test1 --使用變量來接收 return回來的值
SELECT @p1return
2 帶OUTPUT參數的存儲過程
CREATE PROCEDURE p_2 @str NVARCHAR(20)=NULL OUTPUT,@int INT=NULL OUTPUT AS SET @str='say hi'; SET @int =1024; DECLARE @p1 NVARCHAR(20),@p2 INT --聲明兩個變量 --執行 EXECUTE p_2 @p1 OUTPUT,@p2 OUTPUT --變量后有OUTPUT SELECT @p1,@p2 --結果 ------------------------ (無列名) (無列名) say hi 1024 --執行 EXECUTE p_2 @p1 ,@p2 --注意這里沒有OUTPUT SELECT @p1,@p2 --結果 ----------------------- (無列名) (無列名) NULL NULL
3 存儲過程中產生了一個結果集(注: select c1 from table 在存儲過程中 執行兩次,其實也算是一個結果集)
CREATE PROCEDURE p_3 AS SELECT 1 id,'xiaoli' name UNION SELECT 2 id,'xiaowang' name --注意如果有兩次查詢,那么這兩次查詢返回的數據表的結構必需是一樣的. SELECT 3 id,'xiaozhang' name UNION SELECT 4 id,'xiaozhao' name --執行 --這里使用的是表變量,當然使用臨時表,實體表都是可以的. DECLARE @tab AS TABLE( id int ,name nvarchar(20) ) INSERT INTO @tab(id,name) EXECUTE p_3 SELECT * FROM @tab --結果 ---------------------- id name 1 xiaoli 2 xiaowang 3 xiaozhang 4 xiaozhao
4存儲過程中產生了兩個結果集
這個就很麻煩了,因為兩個結果集數據表結構不一樣,所以無法使用第3種方法. 這里使用了xml技術進行變通.
In the life of every software engineer, there should be at least (I’d love to say “at most" actually) one project where bussiness logic is implemented on database side. My current project is one of that kind. We have all logic designed as stored procedures, then there’s a middleware where we use LINQ2SQL for database API bindings, then there are iPhone application and a web-site. Well, it works. But it’s a hell. First of all, T-SQL itself is a very primitive low-level language. There are just no features to make components reusable. So, as long as your procedures are just couple of select statements, everything’s fine. But the more execution flows you have to implement, the more unreadable your procedure becomes. I do firmly believe that being extremely pedantic can make things better, but it doesn’t solve the problem completely. It’s just fine to make mistakes when you write a program. In most cases you have an easy way to cover your code with automated tests, at least it’s pretty straighforward in high-level languages. With T-SQL, you just can’t. In our project, I had to take testing tasks as one of my concerns. I finally came out with idea that the easiest approach technically is just to test the middleware+database together. Test suite is just another client like iPhone application or web-site. This approach proved its adequacy, but the problem is, when Teamcity says things like Test "CanTransferLotsOfMoneys" failed, database guys have no idea what it means. So, for a long time I’ve been trying to find out a solution to write tests for stored procedure in pure T-SQL. In this case, I could have gotten rid of being the only person to intepret test failure. The major point was, in T-SQL it’s just impossible to access multiple result sets if stored procedure returns them. In our project, there are 2 or may be 3 procedures, which only return 1 result set. That’s the issue. Always return only one result set Sure this will never work. Simple example is, I need to get data to render a blog post page. I’ll need: Current user’s details Post details Comments and their details There are at least 3 result sets. Use temporary tables This will probably work, but what do you do if some procedures call themselves recursively? Table variables Table variables is a great idea: declare @Users table( UserId int, UserName nvarchar(256) ) exec DoSomething @Users But unfortunately stored procedures can’t return them. I finally discovered that T-SQL has features to work with XML. The solution consists of few simple ideas. There’s a type xml in T-SQL. This type allows storing XML documents and accessing their nodes. Objects of this type can be either converted to nvarchar() or constructed from it. Objects of this type can be passed to stored procedures as output parameters. You can easily generate XML from select queries. Let’s say we have 2 tables: create table Blog( BlogId int identity(1,1) not null, BlogName nvarchar(256) ) create table Post( PostId int identity(1,1) not null, BlogId int not null, -- yes, this should be FK BlogName nvarchar(256) ) The task is: Create a testable stored procedure GetBlogWithDetails @blogId, that will return BlogId, BlogName and all its posts. Definition of “testable" is: I can access all the data returned and based on this data make some conclusions. Normally, this procedure would look like this: (no error handling - sorry) create procedure GetBlogWithDetails(@BlogId int) as begin select BlogId, BlogName from Blog where BlogId = @BlogId select PostId, BlogId, PostName from Post where BlogId = @BlogId end You can’t access its second result set. The solution is to render same data as XML and return this XML as output parameter. create procedure GetBlogWithDetailsXml( @blogId int, @xml xml output) as begin -- first, create 2 table variables for blogs and for posts declare @blogRows table(BlogId int, BlogName nvarchar(256)) declare @postRows table(PostId int, BlogId int, PostName nvarchar(256)) -- (#1) this is where you implement your useful logic insert into @blogRows select BlogId, BlogName from Blog where BlogId = @blogId insert into @postRows select PostId, BlogId, PostName from Post where BlogId = @blogId -- here you render your 2 tables containing useful data as XML declare @blogRowsXml xml = ( select BlogId, BlogName from @blogRows as Blog for xml auto) declare @postRowsXml xml = ( select PostId, BlogId, PostName from @postRows as Post for xml auto) -- here you build a single XML with all the data required set @xml = cast(@blogRowsXml as nvarchar(max)) + cast(@postRowsXml as nvarchar(max)) -- (#2) here you return the data as "raw" result sets. select * from @blogRows select * from @postRows end As you see, “useful" code is only at #1 and #2. The rest is bunch of stuff for XML. You can now play with GetBlogWithDetailsXml like this: For my test data, declare @xml xml exec GetBlogWithDetailsXml 1, @xml output select @xml returns XML like this: <Blog BlogId="1" BlogName="Blog #1" /> <Post PostId="1" BlogId="1" PostName="Post #1 in Blog #1" /> <Post PostId="2" BlogId="1" PostName="Post #2 in Blog #1" /> It’s now pretty easy to extract all the data returned: select Col.value('@BlogId', 'int') as BlogId, Col.value('@BlogName', 'nvarchar(256)') as BlogName from @xml.nodes('/Blog') as Data(Col) select Col.value('@PostId', 'int') as PostId, Col.value('@BlogId', 'int') as BlogId, Col.value('@PostName', 'nvarchar(256)') as PostName from @xml.nodes('/Post') as Data(Col) with my test data, it returns: BlogId BlogName 1 Blog #1 PostId BlogId PostName 1 1 Post #1 in Blog #1 2 1 Post #2 in Blog #1 I’m not really sure if returning “raw" result sets even makes sense with this approach. From the viewpoint of LINQ2SQL, yes, you won’t be able to utilize its mapping feature, but deserializing object from XML is a primitive task, so it shouldn’t be an issue.
2、
3、
4、
5、