Как я могу получить имена столбцов и данные строк по порядку с помощью DBI в Perl?

Я использую DBI для запроса базы данных SQLite3. То, что у меня есть, работает, но не возвращает столбцы по порядку. Пример:

Query:  select col1, col2, col3, col4 from some_view;
Output:

    col3, col2, col1, col4
    3, 2, 1, 4
    3, 2, 1, 4
    3, 2, 1, 4
    3, 2, 1, 4
    ...

(values and columns are just for illustration)

Я знаю, что это происходит, потому что я использую хэш, но как еще мне вернуть имена столбцов, если я использую только массив? Все, что мне нужно, это получить что-то вроде этого для любого произвольного запроса:

    col1, col2, col3, col4
    1, 2, 3, 4
    1, 2, 3, 4
    1, 2, 3, 4
    1, 2, 3, 4
    ...

(То есть мне нужен вывод в правильном порядке и с именами столбцов.)

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

Вот урезанная версия того, что у меня есть на данный момент:

use Data::Dumper;
use DBI;

my $database_path = '~/path/to/db.sqlite3';

$database = DBI->connect(
  "dbi:SQLite:dbname=$database_path",
  "",
  "",
  {
    RaiseError => 1,
    AutoCommit => 0,
  }
) or die "Couldn't connect to database: " . DBI->errstr;

my $result = $database->prepare('select col1, col2, col3, col4 from some_view;')
    or die "Couldn't prepare query: " . $database->errstr;

$result->execute
    or die "Couldn't execute query: " . $result->errstr;

########################################################################################### 
# What goes here to print the fields that I requested in the query?
# It can be totally arbitrary or '*' -- "col1, col2, col3, col4" is just for illustration.
# I would expect it to be called something like $result->fields
########################################################################################### 

while (my $row = $result->fetchrow_hashref) {
    my $csv = join(',', values %$row);
    print "$csv\n";
}

$result->finish;

$database->disconnect;

person Benjamin Oakes    schedule 17.02.2010    source источник


Ответы (5)


Замените комментарий «что здесь» и следующий цикл на:

my $fields = join(',', @{ $result->{NAME_lc} });
print "$fields\n";

while (my $row = $result->fetchrow_arrayref) {
    my $csv = join(',', @$row);
    print "$csv\n";
}

NAME_lc дает имена полей в нижнем регистре. Вы также можете использовать NAME_uc для прописных букв или NAME в любом случае, когда база данных решит вернуть их.

Вам также, вероятно, следует использовать Text :: CSV или Text :: CSV_XS вместо того, чтобы пытаться откатить собственный CSV-файл, но это уже другой вопрос.

person cjm    schedule 17.02.2010
comment
Отлично, я попробую. Я бы использовал Text :: CSV, но на данный момент я распечатываю вывод только для целей тестирования. - person Benjamin Oakes; 17.02.2010
comment
Сработало отлично. Еще раз спасибо. Неудивительно, что он не всплыл, когда я искал - Google подавляется такими вещами, как @{ $result->{NAME} }. - person Benjamin Oakes; 17.02.2010
comment
Что ж, место для поиска - search.cpan.org/perldoc?DBI (или ваш местный копия). - person cjm; 17.02.2010
comment
Я наткнулся на это, но так и не нашел решения. Однако теперь я понимаю, что знаю, что искать. - person Benjamin Oakes; 17.02.2010

Определите имена столбцов в ARRAY перед SELECT

В идеале у вас должен быть список столбцов, которые вы SELECT'ing с помощью DBI, и вы бы использовали этот массив.

Если вам нужно получить имена столбцов из самого хэша, это сработает, и вы можете отсортировать его, но нет указания на исходный порядок SQL SELECT (в хеш-коде):

my %cols_hash = ("name" => "john", "age" => 2, "color" => "apalachian");
my $cols_hash_ref = \%cols;  

my @keys = (sort keys %$cols_hash_ref);  
my @vals;  
foreach (@keys){ push @vals, $$cols_hash_ref{$_} };  

Надеюсь это поможет.

Когда я искал, я нашел способ получить имена столбцов из DBI:

$sth = $dbh->prepare($query) or die "Prepare exceptioin: $DBI::errstr!";  
$rv = $sth->execute() or die "Execute exception: $DBI::errstr";  
$res = $sth->fetchall_arrayref();  

# Array reference with cols captions, which were retrived.  
$col_names_array_ref = $sth->{NAME};          

Это должно дать вам имена столбцов в исходном порядке, но я это не тестировал.

person Community    schedule 18.12.2014

Если вы хотите сохранить порядок, но по-прежнему использовать хеш для ссылки на поля по имени, используйте:

$dbh->selectall_arrayref($sql,{ Slice => {} } );

Это даст вам упорядоченный массив хэшей

person Dave Stafford    schedule 27.01.2014

Вы запрашиваете результат в виде хеша. Хэш по своей сути неупорядочен. Возможно, вы хотите вместо этого fetchrow_arrayref.

Фактически, если бы вы посмотрели на keys %$row, вы бы увидели, что соответствующие ключи также вышли из строя. Такова природа хэша ... каждый ключ связан со своим значением, но общий порядок ключей или значений оптимизирован для доступа, а не внешнего порядка.

person Randal Schwartz    schedule 17.02.2010
comment
Из вопроса: я знаю, что это происходит, потому что я использую хеш, но как еще мне вернуть имена столбцов, если я использую только массив? Это последняя часть, с которой у меня проблемы. - person Benjamin Oakes; 17.02.2010
comment
См. Атрибуты дескриптора оператора в документе DBI. - person Randal Schwartz; 17.02.2010
comment
Из того, что я читал в Perl, функции «ключи» и «значения», действующие на один и тот же хэш, гарантированно дают одинаковый порядок элементов в соответствующих массивах, которые они возвращают. Таким образом, одним из приемов будет получение первой строки, получение имен полей, а затем продолжение обработки остальных строк. - person jerseyboy; 14.09.2012
comment
@jerseyboy, это работает только в том случае, если хеш не изменяется между вызовами keys и values. Нет никакой гарантии, что результаты будут одинаковыми между вызовами fetchrow_hashref. - person cjm; 16.01.2014

Вот что я делаю:

    use Data::Dump qw(dump);
    # get column names in array
    my @column_names_array= $sth->{NAME};  
    # print out column names in pretty format
    print "Field names: \n";
    dump(@column_names_array);
person Patrick_870206    schedule 09.06.2015
comment
Хорошо .. это простая иллюстрация. Спасибо! - person Swadhikar; 02.11.2015