Perl - хэш массивов через модуль - PullRequest
2 голосов
/ 21 июля 2011

Я немного новичок в Perl и мне нужна помощь в перемещении моего Hash of Arrays по модулям.

В настоящее время у меня есть модуль БД, который хранит массив следующим образом:

    sub getSourceCriteria {

    my($self) = shift();
    my($sourceId) = shift();
    chomp $sourceId;

    my(%criteria) =();
    $logger->debug("Getting records for Source ID: " . $sourceId);
    $dbh=DBI->connect('dbi:ODBC:StkSkrnDB', 'RTETET', 'XXuser01',{ RaiseError => 1, AutoCommit => 0 }) || \ 
               $logger->err_die("Database connection not made: $DBI::errstr\n");

    my($sth) =    "select a.criteria_id, a.criteria_type, a.criteria_props,a.generalcriteria_id,b.field_id ";
    $sth = $sth . "from t_criteria a, t_sourceMapping b where a.generalcriteria_id = (select generalcriteria_id from t_sourcecriteria where source_id =?) ";
    $sth = $sth . "and a.criteria_id=b.criteria_id";


    my($qry) = $dbh->prepare($sth);
    $qry->execute($sourceId) || $logger->error("Could not query for Source Criteria: $DBI::errstr\n");
    my(@row)=();
    my($tempCount) = 0;

    while ( @row = $qry->fetchrow_array ) {
        $tempCount = scalar @row;
        $logger->debug("Size of retrieved SQL Array : $tempCount");
        $criteria{$row[0]} = \@row;
        ##@{$criteria{$row[0]} } = \@row;


  }

  return %criteria;
}

И у меня есть отдельный Perl-скрипт, который читает вывод SQL из приведенного выше кода:

    foreach my $criteria (keys %criterias) { 
        @temp = exists( $criterias{$criteria} ) ? @{ $criterias{$criteria} } : ();
        ##my $tempStr = exists( $criterias{$criteria} ) ? "Yes" : "No";
        $arraySize = scalar @temp;
        $logger->debug("GENERALCRITERIA_ID is $GENERALCRITERIA_ID and size of array is $arraySize and $temp[0]");
        $genCrit_ID = $temp[$GENERALCRITERIA_ID];
        $logger->debug("Criteria ID $criteria has Gen Criteria ID $genCrit_ID");
        if (0!=$generalCriteria_ID || $generalCriteria_ID != $genCrit_ID ) { ## test for uniqueness
            $generalCriteria_ID = -1;
        }
        else {
            $generalCriteria_ID = $genCrit_ID;
        }
    }# do something with $key and $value 
    $generalCriteria = $generalCriteria_ID;

}

Проблема в том, что я получаю 0 в качестве полученного размера массива (2-й фрагмент), хотя, когда я сохраняю массив (в 1-м фрагменте), я проверяю и получаю фактический размер массива.

Пожалуйста, любая помощь / разъяснения будет принята с благодарностью.

EDIT Добавлен дополнительный код в код интерфейса БД.

1 Ответ

3 голосов
/ 22 июля 2011

В вашем цикле while вы присваиваете @row и затем сохраняете ссылку на этот массив. Однако каждый раз, когда цикл повторяется, вы заменяете содержимое @row без объявления нового массива. Итак, в конце все ваши ссылки указывают на одно и то же.

В вашем коде здесь:

my(@row)=();
my($tempCount) = 0;

while ( @row = $qry->fetchrow_array ) {
    $tempCount = scalar @row;
    $logger->debug("Size of retrieved SQL Array : $tempCount");
    $criteria{$row[0]} = \@row;
    ##@{$criteria{$row[0]} } = \@row;
}

Каждый раз, когда цикл while повторяется, вы присваиваете новые значения массиву @row. Но поскольку строка my(@row)=(); находится вне цикла, массив @row всегда одинаков. Поэтому каждый раз, когда вы присваиваете массиву, вы меняете то, что хранится во всех ссылках, которые вы уже взяли.

Чтобы исправить проблему, вам нужно объявлять новый массив для каждой итерации. Самый простой способ сделать это - переместить объявление в условие while:

my($tempCount) = 0;

while ( my @row = $qry->fetchrow_array ) {
    $tempCount = scalar @row;
    $logger->debug("Size of retrieved SQL Array : $tempCount");
    $criteria{$row[0]} = \@row;
    ##@{$criteria{$row[0]} } = \@row;
 }

Теперь каждый раз, когда вы берете ссылку \@row, вы будете получать ссылку на новый массив.


Если бы ваш $qry->fetchrow_array метод возвратил ссылку на массив, у вас не было бы проблемы:

my $row;
while ($row = $qry->fetchrow_array) {
    $logger->debug("Size of retrieved SQL Array : ".@$row);
    $criteria{$$row[0]} = $row;  # already a reference
 }

Но я все равно написал бы это как while (my $row = ... в своем собственном коде, так как держать небольшие области видимости - это хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...