下面是我面临的一个问题,我需要使用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";

10-07 15:54