获取存储过程返回值的几种方式

BinBinGo BinBinGo     2022-08-20     688

关键词:

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.

 

详解pandas获取dataframe元素值的几种方法

参考技术A根据行索引和列名,获取一个元素的值根据行索引和列索引获取元素值选取元素,或者行选取元素选取行返回一个series选取行列返回dataframe按索引选取元素获取行的series到此这篇关于详解pandas获取[Dataframe]原文:1、详... 查看详情

django获取post请求值的几种方法

参考技术A这个还有什么获取方法?不就是request.POST[]或者request.POST.get(,NULL)第二个在键不存在的情况下可以设置一个默认的返回值而不是抛出错误。。 查看详情

js-判断js数据类型的几种方式

...定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈中,即按值访问。引用类型:也称为复杂类型,由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此,其值存储在堆中,而存储在... 查看详情

多线程的几种实现方式

...实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实... 查看详情

java多线程实现的几种方式

...实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。1、继承Thread类实现多线程继承Thread类的方法尽管被我列为一种多线程实现方... 查看详情

vue传值的几种方式

props:适用于父组件==>子组件通信由父组件传值子组件在props中接收即可;(由父组件给子组件传递函数类型的props可实现子组件==>父组件传递数据,较为繁琐,不推荐);Non-prop属性:适用于 父组件==>子组件 通信父... 查看详情

获取表单value值的几种方法

参考:https://blog.csdn.net/akikang/article/details/80796331form设置了name属性,比如<formname="art_form"><inputname="user"> 就可以通过varusername=art_form.user.value获取到user的值。 查看详情

activity传值的几种方式(代码片段)

***Activity的传值*第一种:Intent传值主xml文件中设置按钮,点击跳转:<Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/btn_name"android:onClick="send"/>//设置点击跳转事件主Java代码 查看详情

ionic跨页面传值的几种方法

...它来生成缓存对象,缓存对象以key-value的方式进行数据的存储,在整个应用内是单例的,可以在service或者controller中注入这个服务,然后就可以用它来自由的存取对象以及各种变量,下面是一个简单例子 [javascript] viewplain&... 查看详情

react组件传值的几种方式

参考技术A一、父组件传给子组件通过props来传值,这种应用,很多时候我们某个组件在不同的地方用到,但是就只是内容不一样,这样在调用组件就是父组件的时候给各自自己的值就好二、子组件传给父组件父组件通过props向子... 查看详情

springmvc的几种返回方式

packagecom.boventech.learning.controller;importjava.util.HashMap;importjava.util.Map;importorg.springframework.stereotype.Controller;importorg.springframework.ui.Model;importorg.springframework.web.bi 查看详情

列举asp.net页面之间传递值的几种方式?

....QueryString["name"];2、Session传值该方法将每一个数据存储在服务器变量中,可以传输更多的数据,具有很高的安全性,因此常用于用户身份的认证功能中。但是,如果会话变量存储了太多数据,它将消耗太多服务器资源。程... 查看详情

创建线程的常见的几种方式

...接口,此时可知最终也是通过runnable接口调用的,Future帮助获取callable接口执行过程中的返回值或终止callable接口的执行)。future接口的常用的三种方法a:创建Callable接口的实现类,并实 查看详情

java中后台向前端传值的几种方式

一种,放到request、session、application域里面。1、直接放入一个实体(基本类型)2、放入一个集合、数组3、放入JSON(字符串)参考技术A问题太大了,我个人的理解,传画面要显示的值,除了放在response里面,其他的都不合适。至... 查看详情

java存储时间戳的几种方式

参考技术ASimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");StringdateStr=sdf.format(newjava.util.Date()); 查看详情

jquery请求返回的几种方式

页面代码<formid="form1"runat="server"><div><p>Ajax请求ashx返回json数据的常见问题</p><buttontype="button"id="btnrq">点击请求数据</button></div><divid="iddiv"></div>< 查看详情

gridview控件rowdatabound事件中获取列字段值的几种途径

protectedvoidGridView1_RowDataBound(objectsender,GridViewRowEventArgse){if(e.Row.RowType==DataControlRowType.DataRow){e.Row.Attributes.Add("onclick","javascript:alert(‘当前ID为:"+DataBinder.Eval(e.Row.Da 查看详情

数据结构的几种存储方式

...           数据的存储结构是数据结构的一个重要内容。在计算机中,数据的存储结构可以采取如下四中方法来表现。1)           顺序存储方式简... 查看详情