【问题标题】:How can I get column names and row data in order with DBI in Perl?如何在 Perl 中使用 DBI 按顺序获取列名和行数据?
【发布时间】:2022-01-26 08:43:55
【问题描述】:

我正在使用 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;

【问题讨论】:

    标签: perl sqlite dbi


    【解决方案1】:

    将“这里发生了什么”注释和以下循环替换为:

    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::CSVText::CSV_XS 而不是尝试滚动您自己的 CSV 文件,但这是另一个问题。

    【讨论】:

    • 太好了,我会试试的。我会使用 Text::CSV,但目前我只是出于测试目的打印输出。
    • 效果很好。再次感谢。难怪我搜索时它没有出现——谷歌被@{ $result->{NAME} }之类的东西呛住了。
    • 嗯,搜索的地方是search.cpan.org/perldoc?DBI(或您的本地副本)。
    • 我遇到了这个问题,但从未在那里找到解决方案。不过,我现在明白了,我知道要寻找什么。
    【解决方案2】:

    在 SELECT 之前在 ARRAY 中定义列名

    理想情况下,您应该有一个使用 DBISELECT'ing 的列的列表,并且您会使用该数组。

    如果您需要从哈希本身获取列名,这将起作用,并且您可以对其进行排序,但没有指示原始 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};          
    

    这应该以原始顺序为您提供列名,但我还没有测试过。

    【讨论】:

      【解决方案3】:

      如果您想保留顺序,但仍使用哈希来按名称引用字段:

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

      这会给你一个有序的哈希数组

      【讨论】:

        【解决方案4】:

        您要求将结果作为哈希值。哈希本质上是无序的。也许你想要fetchrow_arrayref

        事实上,如果您查看过keys %$row,您也会看到相应的键也出现故障。这就是哈希的本质......每个键都与其值配对,但键或值的整体顺序是针对访问优化的,而不是外部顺序。

        【讨论】:

        • 来自问题:“我知道这是因为我使用的是哈希,但是如果我只使用数组,我还能如何取回列名?”这是我遇到问题的最后一部分。
        • 参见 DBI 文档中的“语句句柄属性”。
        • 从我在 Perl 中读到的内容来看,作用于相同散列的“键”和“值”函数保证在它们返回的相应数组中给出相同的元素顺序。所以一个技巧是获取第一行,获取字段名称,然后继续处理其余行。
        • @jerseyboy,只有在对keysvalues 的调用之间未修改哈希时才有效。无法保证调用 fetchrow_hashref 之间的结果是一致的。
        【解决方案5】:

        这是我的工作:

            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);
        

        【讨论】:

          【解决方案6】:
          #!/usr/bin/perl                                                                                                                                                                        
          use strict;
          use warnings;
          use DBI;
          my $database = "your_mysqldb";
          my $username = "your_dbusername";
          my $password = "your_dbpassword";
          my $tblename = "your_mysqldbtable";
          my $dsn = "DBI:mysql:embedded";
          #                                                                                                                                                                                      
          my %attr = ( PrintError=>0,   #turn off error reporting via warn()                                                                                                                     
                       RaiseError=>1);  #turn on error reporting via die()                                                                                                                       
          my $dbh = DBI->connect($dsn,$username,$password,\%attr);
          print "Connected to the MySQL database $database for username $username\n";
          my $sql = "DESCRIBE ".$tblename;
          my $sth = $dbh->prepare($sql);  
          $sth->execute();   #execute the prepared query                                                                                                                                         
          my @heads;
          my $i=0;
          while(my $r = $sth->fetchrow_arrayref()){
              $heads[$i]=$r->[0];
              $i++;
          }
          my $j=0;
          foreach(@heads){
              print "$j $_\n";
              $j++;
          }
          $sth->finish();
          $dbh->disconnect(); #disconnect from mysql db   
          

          【讨论】:

          • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
          猜你喜欢
          • 1970-01-01
          • 2011-06-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多