我是sql的初学者。我创建了如下程序
create procedure testprocedure2 as
select 'one'
select 'three'
select 'five'
当我在数据库中执行查询时它会显示三个结果one three five
。 sql查询是exec TEST_ABC_DB.dbo.testprocedure2
当我在Perl中运行相同的查询时,它只提供一条one
$sth = $dbh->prepare("exec TEST_ABC_DB.dbo.testprocedure2");
$sth->execute();
while (@row= $sth->fetchrow_array())
{
print $row[0]."\t";
print "\n";
}
我不知道是什么问题。我该如何解决?我希望这个答案在yesterday's question
中有所帮助答案 0 :(得分:7)
Since you're using DBD::ODBC,您可以使用more_results
provided by that driver在一个execute
中获取多个查询的结果。
这是他们在文档中显示的示例。
do {
my @row;
while (@row = $sth->fetchrow_array()) {
# do stuff here
}
} while ($sth->{odbc_more_results});
如果我们想对您的示例查询执行此操作,则它几乎相同。您运行存储过程,然后继续do {} while
构造(请注意,这不是块,您不能next
!)。
my $sth = $dbh->prepare("exec TEST_ABC_DB.dbo.testprocedure2");
$sth->execute;
do {
while (my @row = $sth->fetchrow_array()) {
print $row[0]."\t";
print "\n";
}
} while ($sth->{odbc_more_results});
这应打印您的预期结果。
one
three
five
其他一些司机也提供此功能。如果他们这样做,您可以拨打$sth->more_results
,而不是使用如下所述的内部。
DBI本身无法一次返回多个查询的结果。您可以运行它们,但无法获得结果。
如果您的程序中确实需要三个单独的查询并且想要所有结果,那么Shakheer和Shahzad使用UNION
的答案就会被发现。
然而,你的例子可能是人为的。您可能在每个查询中都没有相同数量的列,您需要区分每个查询的结果。
我们必须为此更改SQL和Perl代码。
要使其正常工作,您可以插入其他行,以后可以使用这些行将每个结果堆栈映射到每个查询。
让我们说程序如下:
create procedure testprocedure3 as
select 'one'
select 'three', 'three', 'three'
select 'five', 'five', 'five', 'five', 'five'
每个查询仍然只有一行,但它应该作为示例。使用UNION
方法,它首先变为:
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
填充它们。将它们添加到所有查询中,使它们匹配列数最大的列数。
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中循环它,我们将某些返回。
use Data::Dumper;
my $sth = $dbh->prepare("exec TEST_ABC_DB.dbo.testprocedure3");
$sth->execute;
while ( my $row = $sth->fetchrow_arrayref ) {
print Dumper $row;
}
我们会看到与此类似的输出(我没有运行代码,但手动编写输出):
$VAR1 = [ 'one', undef, undef, undef, undef ];
$VAR1 = [ 'three', 'three', 'three', undef, undef ];
$VAR1 = [ 'five', 'five', 'five', 'five', 'five' ];
我们无法知道哪一行属于查询的哪一部分。所以让我们插入一个分隔符。
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代码的结果如下所示:
$VAR1 = [ 'one', undef, undef, undef, undef ];
$VAR1 = [ '-', '-', '-', '-', '-' ];
$VAR1 = [ 'three', 'three', 'three', undef, undef ];
$VAR1 = [ '-', '-', '-', '-', '-' ];
$VAR1 = [ 'five', 'five', 'five', 'five', 'five' ];
这可能不是分隔符的最佳选择,但它很好地说明了我打算做的事情。我们现在要做的就是把它分成不同的结果。
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开始。
我们迭代所有结果行。这里$row
是 lexical 非常重要。在循环头中使用my
创建必须。 (您正在使用use strict
,对吧?)如果我们看到分隔符,我们会增加$query_index
并继续前进。如果我们没有常规结果行,那么我们会将其粘贴到当前查询索引中的@query_results
数组中。
整体结果是一个包含数组数组的数组。
$VAR1 = [
[
[ 'one', undef, undef, undef, undef ]
],
[
[ 'three', 'three', 'three', undef, undef ]
],
[
[ 'five', 'five', 'five', 'five', 'five' ]
],
];
如果你有实际的查询返回很多行,这开始很有意义。
当然,您不必存储所有结果。您也可以直接在循环中处理每个查询的结果。
免责声明:我没有在此答案中运行任何代码,因为我无法访问SQLServer。它可能包含Perl和SQL中的语法错误。但它确实证明了这种方法。
答案 1 :(得分:2)
您创建的过程返回3个结果集。而你只捕获了1个结果。如果您对集合不感兴趣,请使用UNION ALL
create procedure testprocedure2 as
select 'one'
union all
select 'three'
union all
select 'five'
修改:
如果要捕获从存储过程返回的多个结果集,这是一个用MySQL数据库Multiple data sets in MySQL stored procedures
解释的一个很好的例子答案 2 :(得分:1)