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

发布于 2024-08-08 23:43:42 字数 1063 浏览 5 评论 0原文

我正在 Perl 和 DBI 中编写小片段(SQLite 耶!)

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

这是我用来将结果转储到文本文件的代码:

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”(上面硬编码的),而不是转到“results.txt”(上面硬编码) “塔达.txt”。

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

我所说的甚至可以在 DBI 中使用一些魔法吗?

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

我想要的只是有一个文件名 这给出了一些关于什么查询的提示 它保存的输出。分离依据 表名目前看来是一个不错的方法。

I am writing small snippets in Perl and DBI (SQLite yay!)

I would like to log some specific queries to text files having the same filename as that of the table name(s) on which the query is run.

Here is the code I use to dump results to a text file :

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";
}

Here is how I can call this :

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

What I effectively want is, instead of stuff going to "results.txt" ( that is hardcoded above ), it should now go to "TADA.txt".

Had this been a join between tables "HAI" and "LOL", then the resultset should be written to "HAI.LOL.txt"

Is what I am saying even possible using some magic in DBI?

I would rather do without parsing the SQL query for tables, but if there is a widely used and debugged function to grab source table names in a SQL query, that would work for me too.

What I want is just to have a filename
that gives some hint as to what query
output it holds. Seggregating based on
table name seems a nice way for now.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谁的新欢旧爱 2024-08-15 23:43:42

可能不会。您的 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 就是您想要寻找的。嗯嗯,这个
这是一个坏主意。

Probably not. Your SQL generation code takes the wrong approach. You are hiding too much information from your program. At some point, your program knows which table to select from. Instead of throwing that information away and embedding it inside an opaque SQL command, you should keep it around. Then your logger function doesn't have to guess where the log data should go; it knows.

Maybe this is clearer with some code. Your code looks like:

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' ) );

This doesn't let you do what you want to do. So you should structure
your program to do something like:

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' ) );

The API is the same, but now you have the information you need to log
the way you want.

Also, consider SQL::Abstract for dynamic SQL generation. My code
above is just an example.

Edit: OK, so you say you're using SQLite. It has an EXPLAIN command
which you could parse the output of:

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|

Looks like TableLock is what you would want to look for. YMMV, this
is a bad idea.

他是夢罘是命 2024-08-15 23:43:42

一般来说,在 SQL 中,您无法从结果集中可靠地推断出表名,这既是出于理论原因(结果集可能仅包含计算列),也是出于实际原因(结果集在其数据中从不包含表名,仅包含列名) 。

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

In general, in SQL, you cannot reliably deduce table names from result set, both for theoretical reasons (the result set may only consist of computed columns) and practical (the result set never includes table names - only column names - in its data).

So the only way to figure out the tables used is to stored them with (or deduce them from) the original query.

︶ ̄淡然 2024-08-15 23:43:42

我听说过关于 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;

I've heard good things about the parsing ability of SQL::Statement but never used it before now myself.

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文