gpt4 book ai didi

Perl DBI fetchrow_array 问题

转载 作者:行者123 更新时间:2023-12-02 03:54:03 26 4
gpt4 key购买 nike

我遇到了以下问题。我有一个存储过程,用于更新数据或将数据插入数据库,称为 UpdateData。它看起来大致像这样(虽然经过简化):

CREATE PROCEDURE [dbo].[UpdateData] 
@dataId as int,
@data as int,
AS
BEGIN
SET NOCOUNT ON;
declare @count int
select @count = (select COUNT(*) from DataTable data where data.id = @dataId)
if @count = 1
begin
update DataTable set data = @data from DataTable where data.id = @dataId
select 'Updated' [operation] , @@ROWCOUNT [count]
end
else
begin
insert into DataTable (id, data) values(@dataId, @data)
select 'Inserted' [operation] , @@ROWCOUNT [count]
end
END

我通过准备好的语句迭代我的数据,使用 DBI 从 perl 调用这个存储过程。然后,我调用 fetchrow_array 来获取有关执行了哪个操作的信息:

my $dbh = getDBHandle($debug);
foreach (@Data) {
$updateData->execute($->[0], $_->[1]);
my @row = $updateData->fetchrow_array;
my ($action, $count) = ($row[0], $row[1]);
print $row[0] .",$action, $count\n";
}

发生的情况是,一旦运行了任何更新语句,随后所有操作插入的描述都会被截断,从“插入”到“插入”。我认为这是因为字符串 'updated' 的字符比 'inserted' 少一个,并且一旦在列中使用该字符串调用 fetchrow_array 它将重置某种限制。如果我使两个描述字符串之间的差异超过一个章程,比如修改存储过程以使用“更新”而不是“更新”(两个字符与“插入”的差异)

select 'Update' [operation] ,  @@ROWCOUNT [count]

我得到错误:

   DBD::ODBC::st fetchrow_array failed: [Microsoft][ODBC SQL Server Driver]String data, right truncation (SQL-01004)

所以总而言之,输出看起来像

1,插入,10

2,更新,15

3,插入,20

4,更新,5

关于为什么执行不是独立的以及解决此问题的最佳方法是什么的任何想法。我知道我可以使操作相同,但我想要一个更好的解决方案。

编辑:跟进问题。如果 UpdateData 过程需要调用另一个也返回数据的过程。是否有可能在 Perl 中获得两个结果集。一种来自内部程序,一种来自外部程序。现在,>fetchrow_array 仅获取内部结果集。

编辑 2:关于数据截断的原始问题,我想知道为什么在每次执行后调用 $updateData->finish 不会导致每次执行时重置宽度。浏览器

  foreach (@Data) {
$updateData->execute($->[0], $_->[1]);
my @row = $updateData->fetchrow_array;
my ($action, $count) = ($row[0], $row[1]);
print $row[0] .",$action, $count\n";
$updateData->finish;
}

最佳答案

当我们不知道表中的数据时,很难尝试重现您的问题。对于此类问题,最好尝试编写一个小的自包含脚本来演示问题。当我尝试猜测您的场景并运行时:

use DBI;
use strict;
use warnings;

my $h = DBI->connect('dbi:ODBC:xx','xx','xx',
{RaiseError => 1, PrintError => 0});

eval {
$h->do(q/drop table mje/);
$h->do(q/drop procedure pmje/);
};

$h->do(<<'EOT');
create table mje (id int, data int)
EOT

#my @data = (1,1,2);
#my $s = $h->prepare(q/insert into mje (id, data) values(?,?)/);
#foreach (@data) {
# $s->execute($_, $_);
#}

$h->do(<<'EOT');
CREATE PROCEDURE pmje (
@dataId as int,
@data as int)
AS
BEGIN
SET NOCOUNT ON;
declare @count int
select @count = (select COUNT(*) from mje where id = @dataId)
if @count = 1
begin
update mje set data = @data from mje where id = @dataId
select 'Updated' [operation] , @@ROWCOUNT [count]
end
else
begin
insert into mje (id, data) values(@dataId, @data)
select 'Inserted' [operation] , @@ROWCOUNT [count]
end
END
EOT

my $s = $h->prepare(q/{call pmje(?,?)}/);
my @data = (1,2,1);
foreach (@data) {
$s->execute($_, $_);
my @row = $s->fetchrow_array;
my ($action, $count) = ($row[0], $row[1]);
print $row[0] .",$action, $count\n";
}

我得到:

Inserted,Inserted, 1
Updated,Updated, 1
Inserted,Inserted, 1

但是,我可能没有使用与您相同的 ODBC 驱动程序(我在 Linux 上使用的是 Easysoft SQL Server 驱动程序)。您看到的截断错误表明 DBD::ODBC 用太小的缓冲区绑定(bind)了列。 DBD::ODBC 使用 SQLDescribeCol 来获取所需缓冲区的大小,因此在您的情况下,我建议 SQLDescribeCol 返回 7 而不是 8。这应该相当直接地证明您是否启用了 DBD::ODBC 跟踪,但是,您如何做这取决于您的 DBI 和 DBD::ODBC 的最新程度。如果您最近有 DBI 和 DBD::ODBC,只需:

设置 DBI_TRACE=DBD=x.log (windows)或导出 DBI_TRACE=DBD=x.log (unix)

如果在 x.log 中没有产生太多

设置 DBI_TRACE=15=x.log (windows)export DBI_TRACE=15=x.log (unix)

然后运行你的脚本。当我这样做时,我得到这样一行:

   DescribeCol column = 1, name = operation, namelen = 9, type = VARCHAR(12), precision/column size = 8, scale = 0, nullable = 0

它告诉我为该列返回的缓冲区大小是 8。您之前可能是 7,现在是 128。我认为没有任何问题,例如 ODBC 驱动程序或数据库如何知道缓冲区应该有多大?

关于Perl DBI fetchrow_array 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13458753/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com