Perl SQL::Parser表别名替换:适用于SELECT列名,但不适用于WHERE列名

Perl SQL::Parser表别名替换:适用于SELECT列名,但不适用于WHERE列名,sql,perl,parsing,Sql,Perl,Parsing,我试图解析一些存储在日志数据库中的SQL查询——我不想将它们提交到SQL数据库,只是为了提取SELECT和WHERE子句中使用的字段 我一直在用Java、Python和Perl处理几个SQL解析器。对于我的问题来说,SQL::Parser和SQL::Statement似乎更有效。通过这些,我能够编写以下代码: #!/usr/bin/perl use strict; use SQL::Parser; use SQL::Statement; use Data::Dumper; my $sql

我试图解析一些存储在日志数据库中的SQL查询——我不想将它们提交到SQL数据库,只是为了提取SELECT和WHERE子句中使用的字段

我一直在用Java、Python和Perl处理几个SQL解析器。对于我的问题来说,SQL::Parser和SQL::Statement似乎更有效。通过这些,我能够编写以下代码:

#!/usr/bin/perl

use strict;
use SQL::Parser;
use SQL::Statement;

use Data::Dumper;

my $sql = "SELECT sl.plate,sp.fehadop FROM sppLines AS sl ".
          "JOIN sppParams AS sp ON sl.specobjid = sp.specobjid ".
          "WHERE fehadop < -3.5 ";

my $parser = SQL::Parser->new();
my $stmt = SQL::Statement->new($sql,$parser);
printf("COMMAND [%s]\n",$stmt->command);
printf("COLUMNS \n");
my @columns = @{$stmt->column_defs()};
foreach my $column ( @columns) 
  {
  print "   ".$column->{value}."\n";
  }
printf("TABLES \n");
my @tables = $stmt->tables();
foreach my $table ( @tables) 
  {
  print "   ".$table->{name}."\n";
  }
printf("WHERE COLUMNS\n");
my $where_hash = $stmt->where_hash();
print Dumper($where_hash);
抱歉,如果它太长,这是我能想出的最小、独立的例子

此代码的输出为:

COMMAND [SELECT]
COLUMNS 
   spplines.plate
   sppparams.fehadop
TABLES 
   spplines
   sppparams
WHERE COLUMNS
$VAR1 = {
          'arg1' => {
                      'value' => 'fehadop',
                      'type' => 'column',
                      'fullorg' => 'fehadop'
                    },
          'op' => '<',
          'nots' => {},
          'arg2' => {
                      'str' => '-?0?',
                      'fullorg' => '-3.5',
                      'name' => 'numeric_exp',
                      'value' => [
                                   {
                                     'fullorg' => '3.5',
                                     'value' => '3.5',
                                     'type' => 'number'
                                   }
                                 ],
                      'type' => 'function'
                    },
          'neg' => 0
        };
解析器返回通过调用$stmt->column_defs获得的列的名称,这些列已经用实际表名重命名,例如spplines.plate而不是s1.plate-这就是我想要的

我还需要WHERE子句中使用的列的名称。 我已经知道如何递归地解析$stmt->where_hash的结果,其中没有包含代码以使帖子清晰,但即使从转储其内容中,我也可以看到列名与表没有关联

我希望确保WHERE子句中的列名前面也有表名。解析$stmt->where_hash的结果后,我将获得sppparams.fehadop而不是fehadop

这在SQL::Parser中是可能的吗

谢谢
大编辑-试图使问题更清楚

,因为SQL::语句有一个eval_,我想可能有更好的方法,但您可以尝试这样的函数:

get_column($stmt->column_defs(), $where_hash->{arg1});

sub get_column {
    my ($columns, $arg) = @_;
    return $arg->{fullorg} if ($arg->{type} ne 'column');
    foreach my $col (@$columns) {
        return $col->{value} if ($col->{fullorg} eq $arg->{fullorg});
        my ($name) = ( $col->{fullorg} =~ /([^.]+)$/);
        return $col->{value} if ($name eq $arg->{fullorg});
    }
    return $arg->{fullorg};
}

你能用更清晰的方式添加预期的输出吗?问题的下半部分有点含糊不清。我已经编辑了这个问题,希望它更清楚。谢谢-对于我发布的简单案例有效。我必须考虑处理更复杂的WHERE条款。我不确定eval_where是否有用。在这种情况下,我只需要提取完整的列名,而不需要计算它是否匹配值,除非我误解了eval_where的作用-文档和示例很少!我的意思是,因为它们有一个eval函数,所以它们可能在源代码的某个地方有一个深层的解析。我没有读那么深。如果它不适用于您的其他情况,请告诉我。感谢您的提示-我可能需要从该模块获取源代码并进行检查。我刚刚发现解析器抱怨从中选择前10x,Y。。。错误:错误的表或列名:“TOP 10”的字符不是字母数字或下划线-我认为select TOP是标准SQL。这里的答案有点长,所以应该在新问题中。