我可以使用Perl的DBI从SQL查询中获取表名吗?

时间:2009-10-18 13:25:29

标签: perl sqlite dbi

我正在用Perl和DBI编写小片段(SQLite yay!)

我想将一些特定查询记录到与运行查询的表名具有相同文件名的文本文件中。

以下是我用于将结果转储到文本文件的代码:

sub dumpResultsToFile {
    my ( $query ) = @_;

    # Prepare and execute the query
    my $sth = $dbh->prepare( $query );
    $sth->execute();

    # Open the output file
    open FILE, ">results.txt" or die "Can't open results output file: $!";

    # Dump the formatted results to the file
    $sth->dump_results( 80, "\n", ", ", \*FILE );

    # Close the output file
    close FILE or die "Error closing result file: $!\n";
}

以下是我可以称之为:

dumpResultsToFile ( <<"    END_SQL" );
    SELECT TADA.fileName, TADA.labelName
    FROM   TADA
    END_SQL

我真正想要的是,而不是转到“results.txt”(上面是硬编码)的东西,它现在应该转到“TADA.txt”。

如果这是表“HAI”和“LOL”之间的连接,那么结果集应写入“HAI.LOL.txt”

我在DBI中使用一些魔法甚至可以说是什么?

我宁愿不解析表的SQL查询,但是如果有一个广泛使用和调试的函数来在SQL查询中获取表名,那对我也有用。 / p>

我想要的只是拥有一个文件名 这提供了一些关于什么查询的提示 输出它持有。 Seggregating基于 表名似乎是一个很好的方式。

3 个答案:

答案 0 :(得分:4)

可能不是。您的SQL生成代码采用了错误的方法。您从程序中隐藏了太多信息。在某些时候,您的程序知道从哪个表中进行选择。您应该保留它,而不是将信息丢弃并将其嵌入到不透明的SQL命令中。然后你的记录器功能不必猜测日志数据应该去哪里;它知道

使用某些代码可能会更清楚。您的代码如下:

sub make_query {
    my ($table, $columns, $conditions) = @_;
    return "SELECT $columns FROM $table WHERE $conditions";
}

sub run_query {
    my ($query) = @_;
    $dbh->prepare($query);
    ...
}

run_query( make_query( 'foo', '*', '1=1' ) );

这不会让你做你想做的事。所以你应该结构化 你的程序可以做类似的事情:

sub make_query {
    my ($table, $columns, $conditions) = @_;
    return +{
        query => "SELECT $columns FROM $table WHERE $conditions",
        table => $table,
    } # an object might not be a bad idea
}

sub run_query {
    my ($query) = @_;

    $dbh->prepare($query->{query});
    log_to_file( $query->{table}.'.log', ... );

    ...
}

run_query( make_query( 'foo', '*', '1=1' ) );

API是相同的,但现在您拥有了记录所需的信息 你想要的方式。

另外,请考虑SQL::Abstract进行动态SQL生成。我的代码 上面只是一个例子。

编辑:好的,所以你说你正在使用SQLite。它有一个EXPLAIN命令 你可以解析输出:

sqlite> explain select * from test;
0|Trace|0|0|0|explain select * from test;|00|
1|Goto|0|11|0||00|
2|SetNumColumns|0|2|0||00|
3|OpenRead|0|2|0||00|
4|Rewind|0|9|0||00|
5|Column|0|0|1||00|
6|Column|0|1|2||00|
7|ResultRow|1|2|0||00|
8|Next|0|5|0||00|
9|Close|0|0|0||00|
10|Halt|0|0|0||00|
11|Transaction|0|0|0||00|
12|VerifyCookie|0|1|0||00|
13|TableLock|0|2|0|test|00|
14|Goto|0|2|0||00|

看起来TableLock是您想要查找的内容。 YMMV,这个 是一个坏主意。

答案 1 :(得分:4)

通常,在SQL中,由于理论原因(结果集可能只包含计算列)和实际(结果集永远不包括表名 - 仅列名 - 所以不能从结果集中可靠地推导出表名)它的数据)。

因此,找出所用表格的唯一方法是将它们与原始查询一起存储(或从中推导出来)。

答案 2 :(得分:3)

我听说SQL::Statement的解析能力很好,但我以前从未使用它。

use SQL::Statement;
use strict;
use warnings;

my $sql = <<"    END_SQL";
    SELECT TADA.fileName, TADA.labelName
    FROM   TADA
    END_SQL
my $parser = SQL::Parser->new();
$parser->{RaiseError} = 1;
$parser->{PrintError} = 0;
my $stmt = eval { SQL::Statement->new($sql, $parser) }
    or die "parse error: $@";
print join',',map{$_->name}$stmt->tables;