Как я могу написать подпрограмму для обновлений DBI с переменным количеством аргументов? - PullRequest
3 голосов
/ 17 февраля 2009

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

У меня есть это:

sub row_update {
  my $table = shift;
  my %updates = @_;
  my $placeholders = ...

  $dbh->do("UPDATE $table SET (foo) WHERE (bar)") etc...
}

Есть идеи?

Я просто хочу простую функцию обновления, где я могу отправить x количество аргументов (в виде хэша).

Заранее спасибо!

Ответы [ 4 ]

4 голосов
/ 17 февраля 2009

Что-то вроде этого может быть достаточно хорошо:

sub update {
    my ($dbh, $args) = @_;

    my $table   = $args->{table}   || die 'need table';
    my $updates = $args->{updates} || die 'need updates';

    my @cols = keys %$updates;

    my $query = 'UPDATE $table SET '.
      (join ', ', map { '$_ = ?' } @cols)
      ($args->{where} ? ' WHERE '. $args->{where} : '');

    my $sth = $dbh->prepare($query);

    $sth->execute(map { $updates->{$_} } @cols);

    return $sth;
}

Используйте это как:

my $sth = update $dbh, {
    table   => 'foo',
    updates => {
        col1 => 'new_value',
        col2 => 'another_value',
    },
    where => 'id=42',
};

На самом деле, вы хотите изучить использование ORM как DBIx :: Class . Это сделает гораздо лучшую работу по созданию запросов, чем манипуляции со строками, как это будет.

(Переписывание предложения where для параметризации оставлено читателю в качестве упражнения. Вам также необходимо указать ключи обновления и имя таблицы. Узнайте, почему люди используют ORM?)

Редактировать: Если подумать об этом, вам может понравиться DBIx :: Simple в сочетании с SQL :: Abstract . Это займет меньше усилий по настройке, чем ORM, но все же даст вам много преимуществ.

3 голосов
/ 18 февраля 2009

Если я правильно понимаю вопрос, звучит так, будто вы после SQL :: Abstract . Сначала мы создаем объект SQL::Abstract:

use SQL::Abstract;
my $sql = SQL::Abstract->new;

Теперь, в качестве примера, мы будем использовать его для вставки некоторых данных в таблицу:

my %record = (
    FirstName  => 'Buffy',
    LastName   => 'Summers',
    Address    => '1630 Revello Drive',
    City       => 'Sunnydale',
    State      => 'California',
    Occupation => 'Student',
    Health     => 'Alive',
);

my ($stmt, @bind) = $sql->insert(’staff’,\%record);

В результате:

$stmt = "INSERT INTO staff
                (FirstName, LastName, Address, City,
                 State, Occupation, Health)
                 VALUES (?, ?, ?, ?, ?, ?, ?)";

@bind = ('Buffy','Summers','1630 Revello Drive',
         'Sunnydale',’California','Student','Alive');

Приятно то, что мы можем передать это непосредственно в DBI:

 $dbh->do($stmt, undef, @bind);

Конечно, вы хотите обновлять записи, а не просто вставлять их. К счастью, это тоже довольно просто:

my $table = 'People';

my %new_fields = (
    Occupation => 'Slayer',
    Health     => 'Dead',
);

my %where = (
    FirstName => 'Buffy',
    LastName  => 'Summers',
);

my ($stmt, @bind) = $sql->update($table, \%new_fields, \%where);

$dbh->do($stmt, undef, @bind);

Это производит:

$stmt = 'UPDATE People SET Health = ?, Occupation = ? 
         WHERE ( FirstName = ? AND LastName = ? )';

@bind = ('Dead', 'Slayer', 'Buffy', 'Summers');

Если вам нужна дополнительная информация о SQL::Abstract, я рекомендую вам посмотреть ее CPAN-страницу . Также есть глава в Perl Training Australia Руководство по программированию баз данных на Perl , которое свободно доступно на нашей странице заметок курса .

Всего наилучшего,

Пол

Отказ от ответственности: я управляющий директор Perl Training Australia, и поэтому считаю, что наши заметки о курсе довольно хороши.

1 голос
/ 18 февраля 2009

Другие предлагали обычный подход «построить запрос с правильным числом«? »».

Для большинства подобных запросов метод DBI-> quote забывается, но он может упростить код и в большинстве случаев он не медленнее, чем «правильный» метод заполнителя.

1) Используйте DBI-> quote вместо заполнителей для построения запроса. Например, для простого выбора:

my $sql = "select foo from bar where baz in ("
           . join(",", map { DBI->quote($_) } @bazs)
           . ")";
my $data = $dbh->selectall_arrayref($sql);

2) Как предложил jrockway - используйте ORM, чтобы делать такие вещи низкого уровня для вас. DBIx :: Class или Rose :: DB :: Object, например.

0 голосов
/ 18 февраля 2009

Может помочь атрибут NUM_OF_PARAMS:

"NUM_OF_PARAMS"  (integer, read-only)
     The number of parameters (placeholders) in the prepared
     statement.

Так, например, у меня есть скрипт для запуска произвольного SQL из командной строки, который использует этот код:

my $s = $h->prepare($_);

for my $i (1..$s->{NUM_OF_PARAMS}){
  my $param = shift @ARGV;
  $s->bind_param($i, $param);
  print LOG "Bind param $i using $param.\n"
    or die "can't append to $opt{log}: $!";
}

$s->execute();

Не могу сказать, что использовал другие предложенные модули, поэтому они могут работать лучше.

...