我有一个带有WHERE子句的SQL查询,该子句通常具有包含破折号的值,该破折号作为CHAR(10)存储在数据库中。当我显式调用它时,如下所示:

$sth = $dbh->prepare("SELECT STATUS_CODE FROM MyTable WHERE ACC_TYPE = 'A-50C'");

它可以正常工作并返回我的1行;但是,如果我执行以下操作:

my $code = 'A-50C';
$sth = $dbh->prepare("SELECT STATUS_CODE FROM MyTable WHERE ACC_TYPE = ?");
$sth->execute($code);


或者我这样做:

my $code = 'A-50C';
$sth = $dbh->prepare("SELECT STATUS_CODE FROM MyTable WHERE ACC_TYPE = ?");
$sth->bind_param(1, $code);
$sth->execute();


查询完成,但没有结果。我怀疑这与破折号的解释不正确有关,但是由于我已经使用print "My Content: $code\n";打印了$ code变量,因此无法将其链接到Perl问题,因此可以确认其未进行奇怪的转换。我还尝试为bind_param包括第三个值,如果我指定了ORA_VARCHAR2,SQL_VARCHAR之类的值(尝试了所有可能性),我仍然没有任何结果。如果我将其更改为长格式,即{TYPE => SQL_VARCHAR},则会给我一个错误


DBI :: st = HASH -> bind_param(...):属性参数
'SQL_VARCHAR'不是哈希引用


最后,我尝试以不同的方式使用单引号和双引号以及反引号来转义值,但是没有什么让我获得第一行,只有0。有什么想法吗?在文档或搜索中未找到任何内容。这是oracle供参考。

带有错误检查的代码:

my $dbh = DBI->connect($dsn, $user, $pw, {PrintError => 0, RaiseError => 0})
  or die "$DBI::errstr\n";

# my $dbh = DBI->connect(); # connect

my $code = 'A-50C';
print "My Content: $code\n";
$sth = $dbh->prepare( "SELECT COUNT(*) FROM MyTable WHERE CODE = ?" )
  or die "Can't prepare SQL statement: $DBI::errstr\n";
$sth->bind_param(1, $code);
$sth->execute() or die "Can't execute SQL statement: $DBI::errstr\n";

my $outfile = 'output.txt';
open OUTFILE, '>', $outfile or die "Unable to open $outfile: $!";

while(my @re = $sth->fetchrow_array) {
    print OUTFILE @re,"\n";
}

warn "Data fetching terminated early by error: $DBI::errstr\n"
  if $DBI::err;

close OUTFILE;

$sth->finish();
$dbh->disconnect();


我留下了痕迹,然后回来:

-> bind_param for DBD::Oracle::st (DBI::st=HASH(0x22fbcc0)~0x3bcf48 2 'A-50C' HASH(0x22fbac8)) thr#3b66c8
dbd_bind_ph(1): bind :p2 <== 'A-50C' (type 0 (DEFAULT (varchar)), attribs: HASH(0x22fbac8))
dbd_rebind_ph_char() (1): bind :p2 <== 'A-50C' (size 5/16/0, ptype 4(VARCHAR), otype 1 )
dbd_rebind_ph_char() (2): bind :p2 <== ''A-50' (size 5/16, otype 1(VARCHAR), indp 0, at_exec 1)
    bind :p2 as ftype 1 (VARCHAR)
dbd_rebind_ph(): bind :p2 <== 'A-50C' (in, not-utf8, csid 178->0->178, ftype 1 (VARCHAR), csform 0(0)->0(0), maxlen 16, maxdata_size 0)

最佳答案

您的问题可能是将CHARVARCHAR数据一起比较的结果。

CHAR数据类型是臭名昭著的(应避免使用),因为它以固定长度格式存储数据。永远不要将其用于保存长度可变的数据。在您的情况下,存储在ACC_TYPE列中的数据将始终占用10个字符。当存储长度小于列大小的值(如A-50C)时,数据库将隐式填充字符串,最多10个字符,因此存储的实际值变为A-50C_____(其中_表示空白) )。

您的第一个查询之所以有效,是因为当您使用硬编码文字时,Oracle会自动为您的值右移(A-50C-> A-50C_____)。但是,在第二个使用绑定变量的查询中,您正在将VARCHARCHAR进行比较,并且不会发生自动填充。

为了快速解决此问题,您可以在查询中添加右填充:

SELECT STATUS_CODE FROM MyTable WHERE ACC_TYPE = rpad(?, 10)


长期的解决方案是避免在表定义中使用CHAR数据类型,而改用VARCHAR2

10-04 11:14