从模块构建查询 - 最佳实践

时间:2018-06-03 07:13:41

标签: perl

我有多个查询,可能需要执行多达100行甚至更多行,我正在寻找最佳实践/简单方法将查询从模块导入到我的主文件中,绑定值并执行它们。例:

Sql.pm

package Sql;

use strict;
use warnings;

use Exporter;

our @ISA = qw(Exporter);
our @EXPORT_OK = qw($query);

our $query = "SELECT * 
FROM ?
";

Main.pl

use strict;
use warnings;

use Sql;
#use DBI & connect ;

my $select = $Sql::query;
my $tbl= 'my_tbl';

my $sth = $dbh->prepare($select );
$sth->execute($tbl);

这会给我这个错误:

ct_result(ct_dynamic(CS_PREPARE))在/usr/lib/x86_64-linux-gnu/perl5/5.22/DBD/Sybase.pm第138行返回-205。
DBD :: Sybase :: db prepare failed:服务器消息号= 1087严重性= 16状态= 1行= 1服务器=本地文本=必须声明表变量“@ P1”。服务器消息号= 8180严重性= 16状态= 1行= 1服务器= localtext =无法准备语句。在main.pl第16行。 无法在main.pl第17行的未定义值上调用方法“execute”。

如果我在main.pl

中这样做
my $sth = $dbh->prepare($select);
$sth->bind_param(1, $tbl);
$sth->execute(1);

我得到了同样的错误,但告诉我'无法调用方法'bind_param“对未定义的值'

我做错了什么? 是否有更好/更容易/最佳实践方式来实现我想要做的事情?

由于

1 个答案:

答案 0 :(得分:0)

我希望以下内容足够自我解释:

package My_App::Table_Name;

use feature 'state';
# save performance hit on `prepare` statements
# you said SQL statements of 100+ lines

sub sql_name {
    my $class = shift;
    my $dbh   = shift;
    my %params = @_;

    # do some checking on the params if needed, or use Type::Params::compile

    state $sth = $dbh->prepare( <<    END_OF_SQL ); # 4 spaces for neatness

        SELECT * FROM table_name WHERE col_foo = ? AND col_bar = ?

    END_OF_SQL

    $sth->execute(
        $params{foo},
        $params{bar},
    );
    return $sth->fetchall_hashref('id'); # or what ever
}

1;

然后在你的应用中:

use strict;
use warnings;

use DBI;
use My_App::Table_Name;

my $dbh = ... ; # RaiseError is your friend

my $results = My_App::Table_Name->sql_name($dbh,
    foo => 'abc',
    bar => '123',
);

# $results now contains a HashRef where the keys are the id's from the returned
# rows, each row being a HashRef itself, so you can do things like:

say $results->{42}->{col_foo};

这样,您可以按表名,大多数数据库组织SQL语句 修改在一个表上执行,或者由于一个表内的更改,导致链接在其他地方更新。

在每个模块中,您现在可以创建具有合理名称的子例程,例如

sub create { ... };
sub delete { ... };
sub search_joined_with_table_other { ... };

因此在您的应用中:

My_App::Table_Name->create($dbh,
    foo => 'xyz',
    bar => '345',
);

My_App::Table_Other->delete($dbh, id => 42 );

所以,基本上,你不关心主应用程序中的所有SQL,但很好地将它们移到自己的包中。在你的应用程序中,你甚至不需要知道底层有SQL,你只需要调用类方法。

下一级,将为每个Table_Name包返回Row Objects,并在其上拥有自己的实例方法。

快乐编码并记住TIMTOWTDI(有多种方法可以做到)