2016-01-26 9 views
0

Я получаю странную ошибку в своем коде, которая, кажется, происходит только тогда, когда я пытаюсь выполнить запрос с заполнителями и идентификатором цитаты. Я написал следующую подпрограмму, чтобы проверить, если запись существует, и она будет возвращать ключ, если он существует, или null, если он не делает:Невозможно определить заполнители в perl DBI

sub check_exists { 
    my $table=$_[0]; #table 
    my $col=$_[1]; 
    my $check=$_[2]; #query for item 
    #check if value exists 
    my $sql=sprintf(qq(SELECT COUNT(1) FROM %s WHERE ?=?), 
        $dbh->quote_identifier($table)); 
    my $sth = $dbh->prepare($sql); 
    $sth->execute($col,$check);  
    my $result=$sth->fetch()->[0]; 
    $sth->finish();   
    #if value exists find the row and return the primary key 
    if ($result){ 
     my $sql = sprintf(qq(SELECT %s FROM %s WHERE ?=?), 
        $dbh->quote_identifier=$col, 
        $dbh->quote_identifier=$table); 
     my $sth2=$dbh->prepare($sql); 
     $sth2->execute($col,$check);   
     return ($sth2->fetch()->[0]); #return key 
    } 
    else { 
     return 0; #else value does not exist and return null 
    }  
} 

Я даже пробовал:

my $result=$dbh->selectrow_array(sprintf(qq(SELECT COUNT(1) FROM %s WHERE ?=?),$dbh->quote_identifier($table)),undef, $col, $check); 

К сожалению, это всегда всегда возвращает ноль. Если я не использую заполнители, это работает.

my $test=$dbh->selectrow_array(qq(SELECT COUNT(1) FROM ORF1 WHERE idORF1=?),undef,$orf1_crc32) 

Может кто-нибудь объяснить, что я сделал неправильно?

+4

[Как правило, вы не можете использовать заполнители для имен столбцов.] (Https://metacpan.org/pod/DBI#Placeholders-and-Bind-Values) – ThisSuitIsBlackNot

+0

Как отмечено выше, вы не можете использовать заполнители для столбца имена или имена таблиц. Вы можете использовать только заполнители для значений. –

+0

Я думал, вы можете использовать quote_identifier для таблиц и столбцов. – nchuang

ответ

0

Если вы правильно скопировали код.

my $sql = sprintf(qq(SELECT %s FROM %s WHERE ?=?), 
        $dbh->quote_identifier=$col, 
        $dbh->quote_identifier=$table); 

выглядит смешно. Держу пари, ты хотел сказать

my $sql = sprintf(qq(SELECT %s FROM %s WHERE ?=?), 
        $dbh->quote_identifier($col), 
        $dbh->quote_identifier($table)); 
+0

Да, вы правы, вот что я хотел сказать – nchuang

1

Я думаю, что вы бы выгоду от упрощения кода и делает его делать то, что имя подпрограммы говорит он (то есть, проверить наличие записи). Ваш второй запрос делает ненужный поиск, чтобы получить известную вам ценность, , потому что вы передали ее подпрограмме.

Почему бы просто не сделать простой count(*), который сегодня оптимизирован для каждой популярной базы данных? Возвращаемое значение zero/falsy означает, что запись не существует, и значение ненулевого/правдивого возврата означает, что это так. Просто.

sub check_exists { 
    my ($table, $col, $val) = @_; 

    my $sql = sprintf(
     q{select count(*) from %s where %s = ?}, 
     $dbh->quote_identifier($table), 
     $dbh->quote_identifier($col) 
    ); 

    return $dbh->selectrow_array($sql, undef, $val); 
} 

if (check_exists('foo', 'bar', 42)) { 
    # do something ... 
} 
+0

Вы правы, я просто использовал 'count (1)', потому что я видел этот код в потоке, относящемся к нахождению одного экземпляра записи. Что касается разрыва двух функций, мне нужно увидеть, существует ли запись, и если она делает какую-то строку. Думаю, я мог бы просто проверить строку и если она выдает ошибку, то я знаю, что она не существует? – nchuang

+0

Моя точка зрения была не столько в вопросе 'count (*)' vs. something else, а в том, что ваша логика была странной. Ваш запрос сводился к 'select foo from bar, где foo = 1' --- если запись существует, есть довольно хороший шанс (например, 100%), что ваше возвращаемое значение будет именно тем, что вы передали.Вы пытаетесь получить первичный ключ строки на основе некоторого столбца _other_? –

+0

О, спасибо. Я вижу, что я сделал, но да, я пытаюсь вернуть первичный ключ, если запись существует. Я предполагаю, что во втором запросе я не выбираю первичный ключ. Это будет работать, только если я ищу только столбец первичного ключа. Теперь я вижу, что было бы лучше разделить его на две функции. Извините, я слишком устал. – nchuang

1

Не используйте заполнители или переменные для имен таблиц или столбцов.

Вместо этого используйте операторы if для выбора между полными SQL-запросами.

Например:

if($option eq 'name'){ 
    $sql = 'SELECT name FROM users WHERE id = ?'; 
} elsif {$option eq 'id'){ 
    $sql = 'SELECT age from users WHERE name = ?'; 
} else { 
    // STUFF 
} 

Это будет генерировать больше строк кода, но ваш код будет гораздо более удобным для чтения.