sql-server - 如何使用Perl获取存储过程结果?

标签 sql-server perl stored-procedures

我是sql初学者。我创建的程序如下

create procedure  testprocedure2 as
select 'one'
select 'three'
select '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有所帮助。

最佳答案

通过驱动程序(例如 DBD::ODBC )

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构造(请注意,这不是一个 block ,您不能 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 填充它们s。将它们添加到所有查询中,以便它们与列数最多的查询中的列数相匹配。

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这里是词汇。它必须使用 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 中的语法错误。但它确实展示了这种方法。

关于sql-server - 如何使用Perl获取存储过程结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41440383/

相关文章:

sql-server - 在 Sql Server 中选择总和为 n 的 x 随机数

c# - Dapper 无法将类型为 'Microsoft.SqlServer.Types.SqlGeography' 的对象转换为类型 'System.Data.Entity.Spatial.DbGeography'

sql - 数据库设计 : Stored Record Edit History (Temporal Data)

perl - 开始 Perl 语法错误

sql-server - 需要在 SQL Server 存储过程中验证美国邮政编码

c# - 本地数据库 : "A network-related or instance-specific error occurred while establishing a connection to SQL Server."

string - 我怎样才能让 if .. else 工作?

perl - 发出数千个 curl 请求的有效方法

mysql - 在 SQuirreL 中调用 MySQL 存储过程

c# - bool doesExist = command.ExecuteScalar() != null 由于某种原因不断评估为 true