【问题标题】:Perl DBI modifying Oracle database by creating a VIEWPerl DBI 通过创建 VIEW 修改 Oracle 数据库
【发布时间】:2012-08-12 17:43:04
【问题描述】:

我编写了一个 Perl 脚本来检查 Oracle 数据库中的数据。因为查询过程很复杂我选择在中间创建一个VIEW。使用这个视图可以大大简化代码。

当我使用 Perl 代码从文件开始查询数据库时,Perl 代码运行良好,例如Perl mycode.pl file_a。 Perl 代码从file_a 读取行并创建/更新视图,直到输入结束。我得到的结果是完全正确的。

当我同时运行时问题来了

perl mycode.pl file_a

perl mycode.pl file_b

访问同一个数据库。根据我的观察,第一个进程使用的VIEW会被第二个进程修改。这两个过程在同一个观点上交织在一起。

有什么建议可以使这两个过程不相互冲突吗?

查询数据库的 Perl 代码通常是这样的,但是每个实际查询中的细节都比较复杂。

my ($gcsta,$gcsto,$cms) = @t; #(details of @t is read from a line in file a or b)

my $VIEWSS = 'CREATE OR REPLACE VIEW VIEWSS AS SELECT ID,GSTA,GSTO,GWTA FROM TABLEA   WHERE GSTA='.$gcsta.' AND GSTO='.$gcsto.' AND CMS='.$cms;

my $querying = q{ SELECT COUNT(*) FROM VIEWSS WHERE VIEWSS.ID=1};

my $inner_sth = $dbh->prepare($VIEWSS);
my $inner_rv  = $inner_sth->execute();

$inner_sth = $dbh->prepare($querying);
$inner_rv  = $inner_sth->execute();

【问题讨论】:

  • 请贴一个代码 sn-p。另外,我认为您不应该每次都创建(或替换)视图,即每次都运行 DDL。

标签: sql perl oracle dbi


【解决方案1】:

你必须

  • 只创建一次视图,随处使用

  • 在您的 SQL 语句中使用占位符,并将实际参数通过调用传递给 execute

这是您的 SQL 的全部内容吗?可能不会,但如果是这样,它确实相当简单。

看看这个重构以获得一些想法。请注意,它使用 here 文档 来表达 SQL。文本结尾的END_SQL 标记前后不得有空格。

如果您的要求比这更复杂,请向我们描述,以便我们更好地帮助您

my $stmt = $dbh->prepare(<<'END_SQL');
SELECT count(*)
FROM tablea
WHERE gsta = ? AND gsto = ? AND cms= ? AND id = 1
END_SQL

my $rv = $stmt->execute($gcsta, $gcsto, $cms);



如果您必须使用视图,那么您应该像以前一样在CREATE VIEW 中使用占位符,并将每组更改都放入一个事务中,这样其他进程就不会干扰。这包括在创建数据库句柄 $dbh 时禁用 AutoCommit,并在所有步骤完成后添加对 $dbh-&gt;commit 的调用

use strict;
use warnings;

use DBI;

my $dbh = DBI->connect('dbi:Oracle:mydbase', 'user', 'pass',
        { AutoCommit => 0, RaiseError => 1 } );

my $make_view = $dbh->prepare(<<'END_SQL');
CREATE OR REPLACE VIEW viewss AS
SELECT id, gsta, gsto, gwta
FROM tablea
WHERE gsta = ? AND gsto = ? AND cms= ? AND id = 1
END_SQL

my $get_count = $dbh->prepare(<<'END_SQL');
SELECT count(*)
FROM viewss
WHERE id = 1
END_SQL

while (<>) {

  my ($gcsta, $gcsto, $cms) = split;

  my $rv = $make_view->execute($gcsta, $gcsto, $cms);
  $rv = $get_count->execute;
  my ($count) = $get_count->fetchrow_array;
  $dbh->commit;
}

【讨论】:

  • 谢谢。前几天我提出了关于使用execute()传递参数动态创建视图的问题。我提到它不适用于我的情况。我转而使用一些 'a'.$var.'b' 来连接我的指令。最后它起作用了。但我相信你提到的就是做这样一个锅的标准。
  • 那你也可以使用do方法,即prepareexecute结合
【解决方案2】:

视图是相同的还是不同的?

如果视图都相同,则只创建一次,或使用 all_views 表检查它是否存在:http://docs.oracle.com/cd/B12037_01/server.101/b10755/statviews_1202.htm#i1593583

您可以轻松地创建一个包含您的 pid 的视图,并使用 $$ 变量作为 pid,但它在计算机之间不会是唯一的,oracle 也有一些唯一的 id,请参阅http://docs.oracle.com/cd/B14117_01/server.101/b10759/functions150.htm,例如 SESSIONID。

但是你真的需要这样做吗?你为什么不准备一个语句然后执行它? http://search.cpan.org/dist/DBI/DBI.pm#prepare

谢谢, 迈克

【讨论】:

  • 谢谢,迈克。我是新手。所以我使用的计划可能有问题。你的建议很有帮助。在此之前,我正在考虑创建一个大的随机数来标识视图,但它仍然不能保证视图 id 是唯一的。
  • SESSIONID 应该是你想要的。但我认为你应该使用准备好的查询,而不是视图。准备好的查询基本上就像一个临时视图。
  • 既然你是新手,如果对你有帮助,别忘了给我的回复投票!
猜你喜欢
  • 2020-04-12
  • 1970-01-01
  • 1970-01-01
  • 2012-08-09
  • 2011-06-13
  • 2016-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多