如何使用Perl获取存储过程结果?
我是 sql 初学者.我创建的程序如下
I'm beginner in sql. I have created the procedure as follows
create procedure testprocedure2 as
select 'one'
select 'three'
select 'five'
当我对数据库执行查询时它显示三个结果一三五
.sql 查询是 exec TEST_ABC_DB.dbo.testprocedure2
When I execute query into the database It shows the three result one three five
. sql query is exec TEST_ABC_DB.dbo.testprocedure2
当我在 Perl 中运行相同的查询时,它只给出一个记录,它是 one
When I run the same query into the Perl it gives only one record which is one
$sth = $dbh->prepare("exec TEST_ABC_DB.dbo.testprocedure2");
$sth->execute();
while (@row= $sth->fetchrow_array())
{
print $row[0]." ";
print "
";
}
我不知道是什么问题.我该如何解决?我希望这个答案有助于 昨天的问题
I don't know what is the problem. How can I fix it? I hope this answer will help in yesterday's question
推荐答案
通过驱动程序(例如 DBD::ODBC)
由于您使用的是 DBD::ODBC,你可以使用 more_results
提供的驱动程序在一次execute
中获取多个查询的结果.
Through the driver (e.g. DBD::ODBC)
Since you're using DBD::ODBC, you can use more_results
provided by that driver to get the results of multiple queries in one execute
.
这是他们在文档中显示的示例.
This is the example they show in the documentation.
do {
my @row;
while (@row = $sth->fetchrow_array()) {
# do stuff here
}
} while ($sth->{odbc_more_results});
如果我们想对您的示例查询执行此操作,它几乎是相同的.你运行你的存储过程,然后继续 do {} while
构造(注意这不是一个块,你不能 next
离开它!).>
If we want to do this with your example queries, it's pretty much the same. You run your stored procedure, and then proceed with the do {} while
construct (note that this is not a block, you cannot next
out of it!).
my $sth = $dbh->prepare("exec TEST_ABC_DB.dbo.testprocedure2");
$sth->execute;
do {
while (my @row = $sth->fetchrow_array()) {
print $row[0]." ";
print "
";
}
} while ($sth->{odbc_more_results});
这应该会打印出您的预期结果.
This should print your expected result.
one
three
five
其他一些驱动程序也提供此功能.如果他们这样做,您可以调用 $sth->more_results
而不是使用如下所述的内部结构.
Some other drivers also provide this. If they do, you can call $sth->more_results
instead of using the internals as described below.
DBI 本身无法同时返回多个查询的结果.您可以运行它们,但无法获得结果.
There is no way for DBI itself to return the result of multiple queries at once. You can run them, but you cannot get the results.
如果您的过程中确实需要三个单独的查询并想要所有结果,Shakheer 和 <一个 href="https://stackoverflow.com/a/41440490/1331451">Shahzad 使用 UNION
是正确的.
If you really need three separate queries in your procedure and want all of the results, the answers by Shakheer and Shahzad to use a UNION
are spot on.
但是,您的示例可能是人为的.您在每个查询中可能没有相同数量的列,您需要区分每个查询的结果.
However, your example is probably contrived. You probably don't have the same amount of columns in each of those queries, and you need to distinguish the results of each of the queries.
我们必须为此更改 SQL 和 Perl 代码.
要让它发挥作用,您可以插入额外的行,稍后您可以使用这些行将每个结果堆栈映射到每个查询.
To get that to work, you can insert additional rows that you can later use to map each stack of results to each query.
假设程序如下所示:
create procedure testprocedure3 as
select 'one'
select 'three', 'three', 'three'
select 'five', 'five', 'five', 'five', 'five'
每个查询仍然只有一行,但它应该作为示例.使用 UNION
方法,它首先变成这样:
This is still just one row per query, but it should do as an example. With the UNION
approach, it first becomes this:
create procedure testprocedure3 as
select 'one'
union all
select 'three', 'three', 'three'
union all
select 'five', 'five', 'five', 'five', 'five'
如果你运行这个,它可能会失败.在 ANSI SQL 中,UNION 需要在其所有查询中具有相同数量的列,所以我假设 SQLServer 也需要这个.我们需要用 NULL
来填充它们.将它们添加到所有查询中,使它们与列数最多的查询中的列数相匹配.
If you run this, it might fail. In ANSI SQL a UNION needs to have the same number of columns in all its queries, so I assume SQLServer also wants this. We need to fill them up with NULL
s. Add them to all the queries so they match the number of columns in the one with the largest number of columns.
create procedure testprocedure3 as
select 'one', NULL, NULL, NULL, NULL
union all
select 'three', 'three', 'three', NULL, NULL
union all
select 'five', 'five', 'five', 'five', 'five'
如果我们现在在 Perl 中使用以下代码循环它,我们将得到一些东西.
If we now loop over it in Perl with the following code, we'll get something back.
use Data::Dumper;
my $sth = $dbh->prepare("exec TEST_ABC_DB.dbo.testprocedure3");
$sth->execute;
while ( my $row = $sth->fetchrow_arrayref ) {
print Dumper $row;
}
我们会看到类似的输出(我没有运行代码,而是手动编写了输出):
We'll see output similar to this (I didn't run the code, but wrote the output manually):
$VAR1 = [ 'one', undef, undef, undef, undef ];
$VAR1 = [ 'three', 'three', 'three', undef, undef ];
$VAR1 = [ 'five', 'five', 'five', 'five', 'five' ];
我们无法知道哪一行属于查询的哪一部分.所以让我们插入一个分隔符.
We have no way of knowing which line belongs to which part of the query. So let's insert a delimiter.
create procedure testprocedure3 as
select 'one', NULL, NULL, NULL, NULL
union all
select '-', '-', '-', '-', '-'
union all
select 'three', 'three', 'three', NULL, NULL
union all
select '-', '-', '-', '-', '-'
union all
select 'five', 'five', 'five', 'five', 'five'
现在 Perl 代码的结果将如下所示:
Now the result of the Perl code will look as follows:
$VAR1 = [ 'one', undef, undef, undef, undef ];
$VAR1 = [ '-', '-', '-', '-', '-' ];
$VAR1 = [ 'three', 'three', 'three', undef, undef ];
$VAR1 = [ '-', '-', '-', '-', '-' ];
$VAR1 = [ 'five', 'five', 'five', 'five', 'five' ];
这可能不是分隔符的最佳选择,但它很好地说明了我打算做什么.我们现在要做的就是将其拆分为单独的结果.
This might not be the best choice of delimiter, but it nicely illustrates what I am planning to do. All we have to do now is split this into separate results.
use Data::Dumper;
my @query_results;
my $query_index = 0;
my $sth = $dbh->prepare("exec TEST_ABC_DB.dbo.testprocedure3");
$sth->execute;
while ( my $row = $sth->fetchrow_arrayref ) {
# move to the next query if we hit the delimiter
if ( join( q{}, @$row ) eq q{-----} ) {
$query_index++;
next;
}
push @{ $query_results[$query_index] }, $row;
}
print Dumper @query_results;
我定义了两个新变量.@query_results
保存所有结果,按查询编号排序.$query_index
是该数组的索引.以0开头.
I've defined two new variables. @query_results
holds all the results, sorted by query number. $query_index
is the index for that array. It starts with 0.
我们迭代所有结果行.$row
在这里是词法 很重要.它必须在循环头中用my
创建.(您正在使用 use strict
,对吗?)如果我们看到分隔符,我们会增加 $query_index
并继续.如果我们没有,我们有一个常规的结果行,所以我们将它粘贴到当前查询索引中的 @query_results
数组中.
We iterate all the resulting rows. It's important that $row
is lexical here. It must be created with my
in the loop head. (You are using use strict
, right?) If we see the delimiter, we increment the $query_index
and move on. If we don't we have a regular result line, so we stick that into our @query_results
array within the current query's index.
整体结果是一个包含数组数组的数组.
The overall result is an array with arrays of arrays in it.
$VAR1 = [
[
[ 'one', undef, undef, undef, undef ]
],
[
[ 'three', 'three', 'three', undef, undef ]
],
[
[ 'five', 'five', 'five', 'five', 'five' ]
],
];
如果您有返回许多行的实际查询,这开始很有意义.
If you have actual queries that return many rows this starts making a lot of sense.
当然,您不必存储所有结果.您也可以直接在循环中处理每个查询的结果.
Of course you don't have to store all the results. You can also just work with the results of each query directly in your loop.
免责声明:我没有运行此答案中的任何代码,因为我无权访问 SQLServer.它可能包含 Perl 和 SQL 中的语法错误.但它确实演示了该方法.
Disclaimer: I've run none of the code in this answer as I don't have access to an SQLServer. It might contain syntax errors in the Perl as well as the SQL. But it does demonstrate the approach.
相关文章