为啥这个 ISQL 命令不能通过 Perl 的 DBI 运行?

Posted

技术标签:

【中文标题】为啥这个 ISQL 命令不能通过 Perl 的 DBI 运行?【英文标题】:Why won't this ISQL command run through Perl's DBI?为什么这个 ISQL 命令不能通过 Perl 的 DBI 运行? 【发布时间】:2009-10-02 19:18:00 【问题描述】:

不久前我在寻找way to insert values into a text field through isql 并最终找到了一些适合我的加载命令。

当我尝试从 Perl 执行它时它不起作用。我收到语法错误。我已经尝试了两种不同的方法,但到目前为止都不起作用。

我在每个循环周期结束时打印出 SQL 语句变量,因此我知道语法是正确的,但只是没有正确理解。

这是我正在测试的最新代码片段:

foreach(@files)


$STMT = <<EOF;
load from $_ insert into some_table
EOF

$sth = $db1->prepare($STMT);
$sth->execute;


@files 是一个数组,其元素是管道分隔文本文件的完整路径/位置(例如 /home/xx/xx/xx/something.txt)

表中的列数与文本文件中的字段数相匹配,类型检查很好(我已经手动加载了测试文件,没有失败)

我得到的错误是:

DBD::Informix::db prepare failed: SQL: -201: A syntax error has occurred.

知道是什么原因造成的吗?


编辑 RET 和 Petr 的答案
$STMT = "'LOAD FROM $_ INSERT INTO table'";
    system("echo $STMT | isql $db")

我不得不把它改成这样,因为 die 命令会强制非自然死亡,并且语句必须用单引号括起来。

【问题讨论】:

docs.hp.com/cgi-bin/doc3k/B3621690095.12892/43 【参考方案1】:

Petr 完全正确,LOAD 语句是 ISQL 或 DB-Access 扩展,因此您无法通过 DBI 执行它。如果你看一下手册,你会发现它对于 SPL、ESQL/C 等也是无效的语法。

不清楚是否必须使用 perl 来执行脚本,或者 perl 只是一种生成 SQL 的便捷方式。

如果是前者,并且你想要一个纯 perl 方法,你必须准备一个 INSERT 语句(它的外观只涉及一个表?),并通过文件啜饮,使用split 打破它进入列并执行准备好的插入。

否则,您可以使用 perl 生成 SQL 并通过 DB-Access 执行它,或者直接使用 system 或将两者包装在 shell 脚本或 DOS 批处理文件中。

系统调用版本

foreach (@files) 
    my $stmt = "LOAD FROM $_ INSERT INTO table;\n";
    system("echo $stmt | dbaccess $database")
            || die "Statement $stmt failed: $!\n";

在批处理脚本版本中,您可以将所有 SQL 写入单个脚本,即:

perl -e 'while(@ARGV)shift; print "LOAD FROM '$_' INSERT INTO table;\n"' file1 [ file2 ... ] > loadfiles.sql
isql database loadfiles.sql

注意,关于文件名引号的注释仅在文件名包含空格或元字符时才相关,这是常见的问题。

另外,isql 和 dbaccess 之间行为的一个关键区别是,当以这种方式执行时,dbaccess 不会在出错时停止,但 isql 会。要使 dbaccess 在出错时停止处理,请在环境中设置 DBACCNOIGN=1。

希望对您有所帮助。

【讨论】:

这很有帮助...我不得不对其进行一些修改...检查我对问题的编辑并更新您的答案,除非您的版本适用于您可能已经测试过的任何版本与【参考方案2】:

这是因为你的查询不是 SQL 查询,它是一个 isql 命令,告诉 isql 解析输入文件并生成 INSERT 语句。

如果您考虑一下,服务器可能位于完全不同的机器上,并且不知道您在说什么文件以及如何访问它。

所以你基本上有两个选择:

    调用 isql 并将 LOAD 命令传递给它 - 非常难看 自己解析文件并生成 INSERT 语句

【讨论】:

我无权访问任何 Informix 来试用它,但基本上是 system('echo load from "'.$file.'" insert into '.$table.' | dbaccess' ) 是什么让它如此“丑陋”?只是您通过 system() 函数转储命令,还是通过系统提示将命令传送到 isql? 如果你只是想加载数据,那么 system() 就可以了。但是,如果您打算从 Perl 脚本运行一些 SQL 查询,无论如何您都将通过 Perl::DBI 进行连接,从而对第三方工具产生不必要的依赖,该工具仅安装在数据库服务器上,使您的脚本不那么通用。此外,如果您打算在上传后进行一些数据验证,您将失去回滚整批数据的选项。【参考方案3】:

请注意,Notes/load.unload 文件与 DBD::Informix 一起分发,其中包含有关如何使用 Perl、DBI 和 DBD::Informix 处理 UNLOAD 操作的指南。让我有些懊恼的是,我看到上面写着“T.B.D”。 (或多或少)用于 LOAD 部分。

正如其他人所说,LOAD 和 UNLOAD 语句被各种客户端工具伪造为看起来像 SQL 语句,但 Informix 服务器本身不支持它们,主要是因为从客户端获取文件的问题机器(可能是 PC)到服务器机器(可能是 Solaris 机器)。

要模拟 LOAD 语句,您需要分析 INSERT INTO Table 部分。如果它列出了列 (INSERT INTO Table(Col03, Col05, Col09)),那么您可以预期加载数据文件中有三个值,它们会进入这三个列。您将准备一个语句“SELECT Col03, Col05, Col09 FROM Table”来获取列的类型。否则,您需要准备一个语句“SELECT * FROM Table”来获取列(及其类型)的完整列表。给定列名和列数,您可以创建和准备合适的插入语句:'INSERT INTO Table(Col03, Col05, Col09) VALUES(?,?,?)'或'INSERT INTO Table VALUES(?,?,?,?,?,?,?,?,?)'。您可以(可以说应该)在第二个中包含列名。

准备就绪后,您现在已经解析了卸载的数据。 SQLCMD 程序中有一个文档可从IIUG Software Archive 获得(它的存在时间比微软的同名新贵程序要长得多)。这相当详细地描述了 UNLOAD 格式。 Perl 能够处理 Informix 使用的任何内容 - 见证与 DBD::Informix 一起分发的 load.unload 文件中的 UNLOAD 信息。

【讨论】:

如果 cron 作业环境不喜欢系统调用 isql 的聚会,我可能不得不最终这样做...... 我最终不得不这样做.... cron 在遇到该系统调用并通过 isql 管道传输该加载命令时非常适合....但是当我运行时,其他人的答案确实有效这是我自己的【参考方案4】:

谷歌搜索一下showed that the syntax for load 在文件名两边加上引号。如果您将语句更改为:

load from '$_' insert into some_table

由于您的语句没有使用占位符,因此您必须自己加上引号,而不是使用 DBI 引用功能。

【讨论】:

没用,但也许我必须做 db.table 语法.....谢谢你的网站,我不知道为什么我错过了 如果您执行手动硬编码语句会发生什么? $dbi->prepare("LOAD FROM 'filename' INTO somedb.some_table")

以上是关于为啥这个 ISQL 命令不能通过 Perl 的 DBI 运行?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过Perl脚本随时随地得知项目进展状态--Perl 发送邮件

为啥 Eclipse 不能识别 $PERL5LIB?

为啥 Perl 文件 glob() 不能在标量上下文中的循环之外工作?

const常量不能被修改,为啥编译还能通过?

为啥 ncat -exec 可以与 shell 脚本一起使用,但不能与 perl 脚本一起使用?

一些 GNUPlot 终端从命令行工作,但从 Perl 调用时不能(管道)