2013-07-06 5 views
-3

필자의 요구 사항은 일부 검사 목록 값을 일부 그룹에 매핑하고자합니다. 다음은 내 코드입니다 :Perl for 루프 내의 변수에 배열의 현재 값을 저장하는 방법

@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(); 
     } 
} 

?

+2

먼저 '자리 표시 자'를 사용하거나 추악 해집니다. 둘째,'$ dbslave'가 데이터베이스 핸들입니까? – hwnd

+0

예 ... $ dbslave는 데이터베이스 핸들입니다. 그냥 삽입하고자하는 현재 값을 가져 오는 방법 : 다음 장소에서 수정이 필요합니다. my $ box_1 = @ box1 and my $ box_2 = @box2; –

+0

DBI를 사용하고 있으며 오류가 있습니까? – hwnd

답변

3

당신은 '상황'에 읽을 필요가 있고, 특히 '스칼라 컨텍스트'과 '배열 상황'이다. 당신은 스칼라 문맥을 제공하는

my $box_1 = @box1; 

, 그리고 스칼라 문맥에서, @box1 배열의 요소 수를 반환

당신은 쓸 때. 당신이 썼다면 :

my($box_1) = @box1; 

당신이 배열 컨텍스트를 제공 할 것이며, 배열 맥락에서, @box1의 첫 번째 요소는 배열 컨텍스트, $box_1의 첫 번째 요소에 할당 될 것이다 - 그리고 @box1의 나머지 요소가 될 것이다 떨어졌다. (이 잘 당신이 계신 일 수있다. 당신이 @selectbox1의 다양한 이름의 각각에 대한 하나의 ID 값을 선택하려고하는 것 같다)

당신이 $box_1을 사용하려는 방법으로 판단하고 코드에서 $box_2 변수를 사용하는 경우 @box1의 모든 값과 @box2의 모든 값을 포함하는 단일 문자열을 얻으려는 경우 작은 따옴표로 묶인 DBI 드라이버에 제공해야합니다.

당신은 사용하여 문자열에 공백으로 구분 된 값을 얻을 수 있습니다 : 당신이 쉼표로 구분 된 값이 필요한 경우

my $box_1 = "@box1"; 

, 당신은 사용할 수 있습니다

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

$" (use English '-no_match_vars';에서 일명 $LIST_SEPARATOR를) 손상을 방지하기 위해 현지화해야합니다. 즉, $box_1의 정의를 할당과 분리해야합니다. 그렇지 않으면를 떠날 때 $box_1이 파괴됩니다.블록).

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

나 : 다음 SQL이 작동 할 수 있도록

이제

, 그것을 보호하기 위해, 당신은 quote 방법을 사용할 필요가 이러한 변경 사항을 조립

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 문은 선택 상자 문자열에 Funn이 없다고 가정합니다. y 문자 (특히 작은 따옴표 없음). @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"); 

또한 함수를 사용해야한다.

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); 
    } 
} 
: 그것은 많은 시간을 한 번 준비하고 사용할 수 있도록 INSERT 문이 자리를 사용하도록 변환해야

#!/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(); 
    } 
} 

: 두 번 하나의 함수로 캡슐화 사용할 수있는 코드에서 눈부신 반복이있다

실제로 두 SELECT 문은 매개 변수화되고 한 번 준비되어 다시 사용해야합니다. 나는 그 변화를 보여주지 않았다. 왜냐하면 나는 게으르다. 그리고 (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을 쉼표로 바꾸어야합니다.

준비된 문이 성공적으로 준비되었는지 확인하는 등의 수정해야 할 사항이 있습니다. 그러나 이것은 Perl에서 DBI를 사용하는 방법에 대한 통찰력을 줄 수 있습니다.

+0

좋은 직장.하지만 OP가 이것을 읽지 못할 것 같은 느낌이 들었습니다. – innaM

+0

감사합니다. 항상 그 위험이 있습니다. 그러나 한 사람은 희망 속에 있습니다. OP에서'my $ box_1 = $ box1 [-1];이라는 메모가 있기 때문에 문제를 해결하면 생각보다 정확할 것입니다. 나는 아마도 크로스 - 조인이 특히 좋은 아이디어는 아니라는 점에 주목해야한다. 일반적으로 특정 문제에 대한 최선의 해결책은 아닙니다. 그러나 이것은 크로스 - 조인 된 데이터를 테이블로 가져 와서 코드 조각이 오래 동안 달성하는 방법에 대한 기술적 인 문제가 아니라 애플리케이션 수준의 문제입니다. –

+0

조나단, 나를 믿어. 나는 너의 희망을 방해하려하지 않았다. – innaM

-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; 
+1

'$ _'는'foreach' 루프에 의해 설정되지 않습니다. 'foreach'는'$ select2'를 배열 값에 설정합니다. 그러므로 루프 밖의'$ current_value' 선언과 내부 할당은 유용하지 않습니다. – AdrianHHH

관련 문제