下面是我面临的一个问题,我需要使用Perl DBI模块解决这个问题:
表格:
c1 c2 c3 c4 c5 c6
__________________
r1 | a b c d e f
r2 | h i j k x m
r3 | n x p q r x
r4 | k l m n p q
任务:确定在任何行中具有值“x”的最左边的列的名称。在这个例子中是c2。
我看到两种方法:
弗斯特
在所有行中选择c1列;
循环检索字段,从最上面开始;
如果任何字段的值为“x”,则返回c1;
否则,对下一列重复1-4;
我如何想象它在Perl中的样子:
my @bind_values=\(my $field);
my $var;
for my $i (1..6) {
$statement="select c$i from table"
$dbh->selectcol_arrayref($statement, undef, @bind_values);
if ($field eq 'x') {$var=$i;last;}
}
return $field;
第二
将变量$var设置为4;
选择从r1到r$var的所有列。
循环遍历返回的字段,从最左边开始;
如果字段的值为“x”,且当前列号小于x,则将当前列号指定给x;
对下一行重复2-5
返回x
我如何想象它在Perl的样子:
my @bind_values;
my $var=6;
my @cols;
for my $i (1..6) {
for (1..$var){push @cols, "c$_"; push @bind_values, my "c$_";}
$statement="select @cols from table"
$dbh->selectrow_array($statement, undef, @bind_values)
for (@bind values){
if ($$_<$var) $var=$$_;
}
}
return $var;
如果我正确理解了手册,
selectcol_array()
实际上对表中的每一行执行单独的SQL调用,因此这两种方法都涉及两级循环。对于更多了解Perl DBI模块内部工作原理的人,我的问题是:
哪种方法的性能更好?
如果有什么意义的话,我正在使用一个MySQL数据库。
编辑:实际表维度可能是c200 x r1000。
编辑2:
另一个想法是:使用LIMIT语句来确定列是否包含带有语句SQL语句本身的字段,例如:
SELECT c1
FROM table
WHERE c1='x'
LIMIT 0,1
此语句应允许确定c1是否包含值“x”。这会将更多的性能负载转移到DB引擎,对吗?这会改善还是恶化性能?
最佳答案
这是一个使用SQLite的版本。我希望同样的代码在MySQL上也能正常工作,不会有什么变化。除非你的餐桌很大,否则它应该很好用,但你没有提到它的尺寸,所以我想它并不是不寻常的。
它只需将表的内容提取到内存中,然后逐个检查每一列,查看是否有任何字段x
,一旦找到该字段,就会打印该列的名称。
use strict;
use warnings;
use DBI;
use List::Util qw/ any /;
my $dbh = DBI->connect('dbi:SQLite:test.sqlite');
my $sth = $dbh->prepare('SELECT * FROM "table"');
$sth->execute;
my $table = $sth->fetchall_arrayref;
my $first_column;
for my $i (0 .. $#{$table->[0]}) {
my @column = map { $_->[$i] } @$table;
if ( any { $_ eq 'x' } @column ) {
$first_column = $sth->{NAME}[$i];
last;
}
}
print $first_column, "\n";
输出
c2
更新
这种方法可能更快,因为它使用数据库引擎搜索包含
x
的列,并且很少有数据加载到内存中use strict;
use warnings;
use DBI;
my $dbh = DBI->connect('dbi:SQLite:test.sqlite');
my @names = do {
my $sth = $dbh->prepare('SELECT * FROM "table"' LIMIT 0);
$sth->execute;
@{ $sth->{NAME_lc} };
};
my $first_column;
for my $col (@names) {
my $sql = qq{SELECT $col from "table" WHERE $col = 'x' LIMIT 1};
my $row = $dbh->selectrow_arrayref($sql);
if ($row) {
$first_column = $col;
last;
}
}
print $first_column, "\n";