【问题标题】:SQL*Plus inside Perl scriptPerl 脚本中的 SQL*Plus
【发布时间】:2010-12-16 04:54:45
【问题描述】:

我正在尝试使用 SQL*Plus 连接到表,并在 Perl 脚本中获取数据并将该输出存储在 Perl 变量中。

在 shell 脚本中我会这样做:

    SQL_RESULT=`sqlplus -s ${CONNECT_STRING} << EOF
    ${SQLPLUS_SETTINGS}
    select foo||'|'||bar ||'|'|| xyz from temp where dfg='some';
    exit;
    EOF`

但是如何在 Perl 中做到这一点?

【问题讨论】:

    标签: perl oracle unix shell sqlplus


    【解决方案1】:

    任何此类问题都应以“我不能使用 DBI,因为...”作为开头,因为如果可能的话,您真的想使用 DBI。您可能有充分的理由不使用它,但也许,我们可以告诉您为什么您的理由不是很好以及如何处理它。话虽这么说,这是执行您所要求的一种方法,使用 fork 和文件句柄,并一次输出一行(警告:如果您对这样的进程打印太多,它可能会由于缓冲区问题而阻塞):

    use strict;
    use warnings;
    
    pipe(my($p_rdr, $c_wtr)) or die "Err: $!";
    pipe(my($c_rdr, $p_wtr)) or die "Err: $!";
    my $pid = fork;
    die "Could not fork: $!" unless defined $pid;
    unless ($pid) {
      close $p_rdr;
      close $p_wtr;
      open(STDOUT, ">&=", $c_wtr) or die "dup: $!";
      open(STDIN, "<&=", $c_rdr) or die "dup: $!";
      print "Exec sqlplus\n";
      exec qw(sqlplus user/passwd@dbname);
      die "Could not exec: $!";
    }
    close $c_wtr;
    close $c_rdr;
    print "Print sql\n";
    print $p_wtr "select * from table_name where col1 = 'something';\n";
    print "Close fh\n";
    close $p_wtr;
    
    print "Read results\n";
    while (<$p_rdr>) {
      print "O: $_";
    }
    close $p_rdr;
    

    【讨论】:

      【解决方案2】:

      有几点:

      • DBI 绝对是最好的方法。但是请注意我之前对一个可能“仍然”相关的 Oracle 问题的回答:How can I use a database server from a Perl CGI script?

      • 如果您的 SQL 太长,SQL*Plus 会引发错误。它有一个固定的行长度缓冲区(我不记得它是什么,但我认为它在 Oracle 8 中低于 2000 个字符)。可能有一种解决方法(拆分线路?配置设置?)但我发现切换到 DBI 是出于这个和其他原因的最佳解决方案。

      警告:以上所有信息均基于 Oracle 8。

      /I3az/

      【讨论】:

        【解决方案3】:

        如果您想针对数据库编写 Perl 脚本,那么使用 DBI 的建议很好,而且绝对是正确的方法。

        但是,要回答您的确切问题,如果您特别想编写 SQL*Plus 脚本,使用 Perl 脚本执行此操作的语法与 shell 版本非常相似

        my $connect_string = 'scott/tiger@test';
        my $sqlplus_settings = '';
        my $result = qx { sqlplus $connect_string <<EOF
        $sqlplus_settings
        select 1 from dual;
        exit;
        EOF
        };
        print $result;
        

        我在那里使用的qx 运算符只是一种更礼貌的反引号形式,大括号分隔块中的所有内容都由子shell 运行,并且输出返回到分配。 Perl 中的变量通常不大写。

        【讨论】:

        • 我也在考虑编写一个shell脚本并返回查询输出结果,我想在perl脚本中调用那个shell脚本。这也可能吗?
        • 当然——反引号或 qx( ) 中的任何内容都将作为子 shell 运行,并且类似地捕获输出。再一次,我不认为这是构建 perl 程序的非常好的方法。
        • 这是对 qx 引用机制的绝妙使用,在一次性脚本场景中,这可能是一个不错的选择。
        【解决方案4】:

        查看 DBI 模块。事实上,有一个专门的网站:dbi.perl.org。另外,请查看the CPAN module reference for DBI

        这是一个代码示例,直接来自the first DBI tutorial on google

            use DBI;
        
            my $dbh = DBI->connect('DBI:Oracle:payroll')
                or die "Couldn't connect to database: " . DBI->errstr;
            my $sth = $dbh->prepare('SELECT * FROM people WHERE lastname = ?')
                or die "Couldn't prepare statement: " . $dbh->errstr;
        
            $sth->execute($lastname)             # Execute the query
                or die "Couldn't execute statement: " . $sth->errstr;
        
            # Read the matching records and print them out          
            while (@data = $sth->fetchrow_array()) {
                my $firstname = $data[1];
                my $id = $data[2];
                print "\t$id: $firstname $lastname\n";
            }
            if ($sth->rows == 0) {
              print "No names matched `$lastname'.\n\n";
            }
            $sth->finish;
            print "\n";
            print "Enter name> ";
        
            $dbh->disconnect;
        

        Perl 也有 EOF 风格的多行注释;您可以像这样进行长查询:

        my $query = <<'END_QUERY';
        ${SQLPLUS_SETTINGS}
        select foo||'|'||bar ||'|'|| xyz from temp where dfg='some';
        exit;
        END_QUERY
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-13
          • 1970-01-01
          • 2019-06-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-11
          相关资源
          最近更新 更多