-3

我的要求是,我想将一些清单值映射到某些组。以下是我的代码:

@selectbox1 => contains the selected select groups
@selectbox2 => contains selected checklist

代码:

foreach $select1(@selectbox1) {
      my $sql_select1 = "select id from group_management where group_name = '$select1'";
      my $box1 = $dbslave -> prepare($sql_select1);
      $box1 -> execute();
      while($select_box1= $box1->fetchrow_array())
      {
          push (@box1,$select_box1);
      }
      my $box_1 = @box1;  # currently I tried like this to store the current value .NEED CORRECTION HERE

      foreach $select2(@selectbox2) {

        my $sql_select2 = "select id from checklist where checklist_name = '$select2'";
        my $box2 = $dbslave -> prepare($sql_select2);
        $box2 -> execute();

        while($select_box2 = $box2->fetchrow_array())
        {
            push (@box2,$select_box2);
        }
        my $box_2 = @box2;  # currently I tried like this to store the current value .NEED CORRECTION HERE

        my $sql_insert = "insert into checklist_group_mapping values ('',$box_2,$box_1)";
        my $ins = $dbslave -> prepare($sql_insert);
        $ins -> execute();
      }
}

如何将数组的当前值分配给变量,以便将其插入映射表?

4

2 回答 2

3

您需要阅读“上下文”,特别是“标量上下文”和“数组上下文”。

当你写:

  my $box_1 = @box1;

您正在提供标量上下文,并在标量上下文中@box1返回数组中的元素数。如果你写:

  my($box_1) = @box1;

您将提供数组上下文,并且在数组上下文中,第一个元素@box1将分配给数组上下文的第一个元素,$box_1而其余元素@box1将被删除。(这很可能是您所追求的;您很可能正尝试为 中的每个不同名称选择单个 ID 值@selectbox1。)

从您尝试在代码中使用$box_1and$box_2变量的方式来看,您希望获得一个包含 from 的所有值的@box1单个字符串和另一个包含from 的所有值的单个字符串@box2,它们可能需要提供给 DBI 驱动程序用单引号括起来。

您可以使用以下方法将空格分隔的值转换为字符串:

my $box_1 = "@box1";

如果您需要逗号分隔的值,您可以使用:

my $box_1;
{ local $" = ","; $box_1 = "@box_1"; }

$"又名$LIST_SEPARATORunder use English '-no_match_vars';)必须本地化以防止损坏,但这意味着您必须将定义$box_1与分配分开(因为如果不这样做,$box_1则在离开{...}块时会被破坏)。

现在,为了保护它以便 SQL 可以工作,您需要使用以下quote方法:

$box1 = $dbslave->quote($box1);

或者:

my $box1 = $dbslave->quote("@box1");

组装这些变化,我们得到:

#!/usr/bin/env perl
use strict;
use warnings;

### Improved, but not operational

# use DBI;

my @selectbox1 = ( "group1", "group2", "group3" );
my @selectbox2 = ( "check1", "check2", "check3" );
my $dbslave;

# $dbslave = DBI->connect(...) or die "A horrible death";

foreach my $select1 (@selectbox1)
{
    my $sql_select1 = "select id from group_management where group_name = '$select1'";
    my $box1 = $dbslave->prepare($sql_select1);
    $box1->execute();
    my @box1;
    while (my $select_box1 = $box1->fetchrow_array())
    {
        push @box1, $select_box1;
    }
    my $box_1 = $dbslave->quote("@box1");

    foreach my $select2(@selectbox2)
    {
        my $sql_select2 = "select id from checklist where checklist_name = '$select2'";
        my $box2 = $dbslave->prepare($sql_select2);
        $box2->execute();

        my @box2;
        while (my $select_box2 = $box2->fetchrow_array())
        {
            push @box2, $select_box2;
        }
        my $box_2 = $dbslave->quote("@box2");

        my $sql_insert = "insert into checklist_group_mapping values ('', $box_2, $box_1)";
        my $ins = $dbslave->prepare($sql_insert);
        $ins->execute();
    }
}

请注意,这两个 SELECT 语句假定选择框字符串不包含有趣的字符(特别是不包含单引号)。如果你负责 and 的内容@selectbox1@selectbox2那没关系。如果它们包含用户输入,您必须清理该输入,或$dbslave->quote()再次使用,或使用占位符。我会忽略这个问题。

您还将标量上下文与 一起使用$box1->fetchrow_array(),这不会产生您想要的答案(尽管fetchrow_array()是上下文敏感的,但手册警告您要小心)。我会使用类似的东西:

    my @box1;
    while (my @row = $box1->fetchrow_array())
    {
        push @box1, $row[0];
    }
    my $box_1 = $dbslave->quote("@box1");

您还需要使用函数。您的代码中有一个明显的重复,可以封装成一个使用两次的函数:

#!/usr/bin/perl
use strict;
use warnings;

# use DBI;

my @selectbox1 = ( "group1", "group2", "group3" );
my @selectbox2 = ( "check1", "check2", "check3" );
my $dbslave;

# $dbslave = DBI->connect(...) or die "A horrible death";

sub fetch_all
{
    my($dbh, $sql) = @_;
    my $sth = $dbh->prepare($sql);
    $sth->execute();
    my @results;
    while (my @row = $sth->fetchrow_array())
    {
        push @results, $row[0];
    }
    my $result = $dbslave->quote("@results");
    return $result;
}

foreach my $select1 (@selectbox1)
{
    my $sql_select1 = "select id from group_management where group_name = '$select1'";
    my $box_1 = fetch_all($dbslave, $sql_select1);

    foreach my $select2(@selectbox2)
    {
        my $sql_select2 = "select id from checklist where checklist_name = '$select2'";
        my $box_2 = fetch_all($dbslave, $sql_select2);

        my $sql_insert = "insert into checklist_group_mapping values ('', $box_2, $box_1)";
        my $ins = $dbslave->prepare($sql_insert);
        $ins->execute();
    }
}

INSERT 语句应转换为使用占位符,以便可以准备一次并多次使用:

my $sql_insert = "insert into checklist_group_mapping values ('', ?, ?)";
my $ins = $dbslave->prepare($sql_insert);

foreach my $select1 (@selectbox1)
{
    my $sql_select1 = "select id from group_management where group_name = '$select1'";
    my $box_1 = fetch_all($dbslave, $sql_select1);

    foreach my $select2(@selectbox2)
    {
        my $sql_select2 = "select id from checklist where checklist_name = '$select2'";
        my $box_2 = fetch_all($dbslave, $sql_select2);
        $ins->execute($box_1, $box_2);
    }
}

实际上,这两个 SELECT 语句也应该参数化并准备一次并重用。我没有展示这种变化,因为(a)我很懒,并且(b)有一个更大的变化仍然更有效。

当我们查看您真正在做什么时,它应该都是一条 SQL 语句:

#!/usr/bin/perl
use strict;
use warnings;

# use DBI;

my @selectbox1 = ( "group1", "group2", "group3" );
my @selectbox2 = ( "check1", "check2", "check3" );
my $dbslave;

# $dbslave = DBI->connect(...) or die "A horrible death";

sub placeholder_list
{
    my($n) = @_;
    die "$n should be larger than 0" if $n <= 0;
    my $list = "(?" . ",?" x ($n - 1) . ")";
    return $list;
}

my $sql_insert = qq%
    INSERT INTO checklist_group_mapping(col1, col2, col3)
        SELECT '', gm.id, cl.id
          FROM group_management AS gm
         CROSS JOIN checklisst AS cl
         WHERE gm.group_name IN X1
           AND cl.checklist_name IN X2
%;

my $X1 = placeholder_list(scalar(@selectbox1));
my $X2 = placeholder_list(scalar(@selectbox2));
$sql_insert =~ s/X1/$X1/;
$sql_insert =~ s/X2/$X2/;

my $ins = $dbslave->prepare($sql_insert);
$ins->execute(@selectbox1, @selectbox2);

这样做的最大优势在于,应用程序和数据库之间的信息流的往返次数要少得多,这(几乎)总是可以显着提高性能。

唯一的遗留问题是您的 DBMS 是否支持这样的显式 CROSS JOIN。如果不是,您需要用一个逗号替换单词 CROSS JOIN。

还有一些事情需要修复,例如检查准备好的语句是否成功准备等等。但这可能使您对如何考虑将 DBI 与 Perl 一起使用有所了解。

于 2013-07-06T16:23:37.733 回答
-4

诀窍是在你的foreach中使用$ _ 变量。像这样:

  my $current_value;
  foreach $select2(@selectbox2) {
        $current_value = $_;
        my $sql_select2 = "select id from checklist where checklist_name = '$select2'";

……

my $box_2 = $current_value;
于 2013-07-06T14:30:00.007 回答