2009-08-20 20 views
5

मेरे पास एक SQL SELECT कथन द्वारा लौटाई गई पंक्तियों पर एक लूप है, और, पंक्ति के डेटा पर कुछ प्रोसेसिंग के बाद, मैं कभी-कभी पंक्ति के मान को अपडेट करना चाहता हूं। लूप के शरीर में प्रसंस्करण गैर-तुच्छ है, और मैं इसे एसक्यूएल में नहीं लिख सकता। जब मैं चयनित पंक्ति के लिए अद्यतन निष्पादित करने का प्रयास करता हूं तो मुझे एक त्रुटि मिलती है (पर्ल के डीबीडी :: SQLite :: st execute विफल: डेटाबेस तालिका लॉक है)। क्या मैं जो करने की कोशिश कर रहा हूं उसे हासिल करने के लिए एक पठनीय, कुशल और पोर्टेबल तरीका है? ऐसा विफल होने पर, क्या ऐसा करने के लिए कोई डीबीडी या SQLite-विशिष्ट तरीका है?मैं एक लूप में एक चयन द्वारा लौटाई गई पंक्तियों को कैसे अपडेट कर सकता हूं?

जाहिर है, मैं अद्यतन को अलग डेटा संरचना में धक्का दे सकता हूं और लूप के बाद उन्हें निष्पादित कर सकता हूं, लेकिन इसके बाद मैं कोड के नफरत से नफरत करता हूं।

यदि आप रुचि रखते हैं, तो संबंधित पर्ल कोड है।

my $q = $dbh->prepare(q{ 
    SELECT id, confLoc FROM Confs WHERE confLocId ISNULL}); 
$q->execute or die; 
my $u = $dbh->prepare(q{ 
    UPDATE Confs SET confLocId = ? WHERE id = ?}); 
while (my $r = $q->fetchrow_hashref) { 
    next unless ($r->{confLoc} =~ m/something-hairy/); 
    next unless ($locId = unique_name_state($1, $2)); 
    $u->execute($locId, $r->{id}) or die; 
} 
+0

आपके द्वारा perl का उपयोग करने में बहुत बुरा, हाइबरनेट आप जो करना चाहते हैं उसके लिए बिल्कुल सही होगा। – Zoidberg

+2

एक आंतरिक रूप से यह अक्षम ऑपरेशन करेगा जो मैं टालने की कोशिश कर रहा हूं। –

+6

@ ज़ॉयडबर्ग, बहुत बुरा हम बेकार टिप्पणियों को कम नहीं कर सकते हैं। – friedo

उत्तर

6

अस्थायी रूप से AutoCommit सक्षम:

 
sqlite> .header on 
sqlite> select * from test; 
field 
one 
two 
#!/usr/bin/perl 

use strict; 
use warnings; 

use DBI; 

my $dbh = DBI->connect('dbi:SQLite:test.db', undef, undef, 
    { RaiseError => 1, AutoCommit => 0} 
); 

test_select_with_update($dbh); 

sub test_select_with_update { 
    my ($dbh) = @_; 
    local $dbh->{AutoCommit} = 1; 
    my $q = $dbh->prepare(q{SELECT field FROM test}); 
    my $u = $dbh->prepare(q{UPDATE test SET field = ? WHERE field = ?}); 
    $q->execute or die; 
    while (my $r = $q->fetchrow_hashref) { 
     if ((my $f = $r->{field}) eq 'one') { 
      $u->execute('1', $f) or die; 
     } 
    } 
} 

के बाद कोड चलाया जा रहा है:

Zoidberg के टिप्पणी के लिए, लेकिन अपने स्विच करने में सक्षम थे, तो जवाब में
 
sqlite> .header on 
sqlite> select * from test; 
field 
1 
two 
2

अधिक पर्ल के DBIx::Class जैसे ओआरएम को तो आप पाते हैं कि आप क्यू कुछ इस तरह ld लिखने:

my $rs = $schema->resultset('Confs')->search({ confLocId => undef }); 

while (my $data = $rs->next) { 
    next unless $data->confLoc =~ m/(something)-(hairy)/; 
    if (my $locId = unique_name_state($1, $2)) { 
     $data->update({ confLocID => $locid }); 
    } 
} 

और DBIx :: कक्षा आपकी कल्पना हड़पने नहीं है अगर वहाँ Fey::ORM तरह CPAN और उदाहरण के लिए Rose::DB पर कुछ और हैं।

2

आपकी समस्या यह है कि आप एक डेटाबेस डेटाबेस हैंडलर का उपयोग कर रहे हैं जब आप फ़ेचिंग लूप में हों।

my $dbh = DBI->connect(...); 
my $dbhForUpdate = DBI->connect(...) ; 

फिर अपने पाश में dbhForUpdate का उपयोग करें:: वैसे भी

while(my $row = $sth->fetch()){ 
    ... 
    $dbhForUpdate->do(...) ; 
} 

, मैं के बाद से वहाँ अच्छा है ऐसा करने की सिफारिश नहीं होगा

तो अद्यतन प्रदर्शन करने के लिए अपने डेटाबेस हैंडलर का एक और उदाहरण है डेटाबेस स्तर पर आप समवर्ती मुद्दों में भाग लेने की संभावना है।

संबंधित मुद्दे

 संबंधित मुद्दे