【问题标题】:How can I export an Oracle table to tab separated values?如何将 Oracle 表导出为制表符分隔值?
【发布时间】:2010-01-06 09:10:22
【问题描述】:

我需要将数据库中的表导出到制表符分隔值文件。我在 Perl 和 SQLPlus 上使用 DBI。它是否支持(DBI 或 SQLPlus)从 TSV 文件导出和导入?

我可以编写代码来满足我的需要,但如果有现成的解决方案,我想使用它。

【问题讨论】:

    标签: perl dbi sqlplus


    【解决方案1】:

    将表转储到具有制表符分隔值的文件应该相对简单。

    例如:

    open(my $outputFile, '>', 'myTable.tsv');
    
    my $sth = $dbh->prepare('SELECT * FROM myTable');
    
    $sth->execute;
    
    while (my $row = $sth->fetchrow_arrayref) {
        print $outputFile join("\t", @$row) . "\n";
    }
    
    close $outputFile;
    $sth->finish;
    

    请注意,如果您的数据包含制表符或换行符,这将无法正常工作。

    【讨论】:

    • 通常最好避免使用原始连接来生成结构化文件,以免任何数据列包含嵌入的选项卡。为避免出现问题,最好使用 Text::CSV_XS 以便列内的分隔符由双引号嵌入。您已正确警告这种情况。使用 Text::CSV_XS 会更健壮
    • 如果任何数据有标签(可能只是来自二进制数据),这会给你带来麻烦。您可以使用 Test::CSV_XS 来构造记录。
    【解决方案2】:

    根据您提供的信息,我猜您正在使用 DBI 连接到 Oracle 实例(因为您提到了 sqlplus)。

    如果您想要一个“现成”的解决方案,最好的办法是使用“yasql”(Yet Another SQLplus)一个基于 DBD::Oracle 的 Oracle 数据库外壳。

    yasql 有一个简洁的功能,您可以编写一个 sql 选择语句并将输出直接从它安装的外壳重定向到 CSV 文件(您需要 Text::CSV_XS)。

    另一方面,您可以使用DBD::OracleText::CSV_XS 滚动您自己的脚本。准备好并执行语句句柄后,您需要做的就是:

    $csv->print ($fh, $_) for @{$sth->fetchrow_array};
    

    假设您已使用制表符作为记录分隔符初始化 $csv。有关详细信息,请参阅Text::CSV_XS 文档

    【讨论】:

      【解决方案3】:

      这是一种仅使用 awk 和 sqlplus 的方法。您可以使用存储 awk 脚本或复制/粘贴 oneliner。它使用 HTML 输出模式,因此字段不会被破坏。

      将此脚本存储为 sqlplus2tsv.awk:

      # This requires you to use the -M "HTML ON" option for sqlplus, eg:
      #   sqlplus -S -M "HTML ON" user@sid @script | awk -f sqlplus2tsv.awk
      #
      # You can also use the "set markup html on" command in your sql script
      #
      # Outputs tab delimited records, one per line, without column names.
      # Fields are URI encoded.
      #
      # You can also use the oneliner
      #   awk '/^<tr/{l=f=""}/^<\/tr>/&&l{print l}/^<\/td>/{a=0}a{l=l$0}/^<td/{l=l f;f="\t";a=1}'
      # if you don't want to store a script file
      
      # Start of a record
      /^<tr/ {
        l=f=""
      }
      # End of a record
      /^<\/tr>/ && l {
        print l
      }
      # End of a field
      /^<\/td>/ {
        a=0
      }
      # Field value
      # Not sure how multiline content is output
      a {
        l=l $0
      }
      # Start of a field
      /^<td/ {
        l=l f
        f="\t"
        a=1
      }
      

      没有用长字符串和奇怪的字符对此进行测试,它适用于我的用例。有进取心的灵魂可以将此技术应用于 perl 包装器:)

      【讨论】:

        【解决方案4】:

        过去我不得不这样做...我有一个 perl 脚本,您可以通过该脚本传递您希望运行的查询并通过 sqlplus 进行管道传输。摘录如下:

        open(UNLOAD, "> $file");      # Open the unload file.
        $query =~ s/;$//;             # Remove any trailng semicolons.
                                      # Build the sql statement.
        $cmd = "echo \"SET HEAD OFF
                     SET FEED OFF
                     SET COLSEP \|
                     SET LINES 32767
                     SET PAGES 0
                     $query;
                     exit;
                     \" |sqlplus -s $DB_U/$DB_P";
        
        @array = `$cmd`;              # Execute the sql and store
                                      # the returned data  in "array".
        print $cmd . "\n";
        clean(@array);                # Remove any non-necessary whitespace.
                                      # This is a method to remove random non needed characters
                                      # from the array
        
        foreach $x (@array)           # Print each line of the
        {                             # array to the unload file.
           print UNLOAD "$x\|\n";
        }
        
        close UNLOAD;                 # Close the unload file.
        

        当然,上面我将其设为管道分隔符...如果您想要标签,您只需要 \t 而不是 |在印刷品中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-08-31
          • 2021-07-17
          • 1970-01-01
          • 2021-02-23
          • 1970-01-01
          • 2021-08-26
          • 2021-07-21
          相关资源
          最近更新 更多