如何使用Perl从SQL中提取字段名称?

时间:2010-02-01 00:34:10

标签: sql regex perl

我在文本文件中有一系列select语句,我需要从每个select查询中提取字段名称。如果某些字段没有使用to_char()等嵌套函数,那么这将很容易。

给定select语句字段可以有几个嵌套括号,如:

ltrim(rtrim(to_char(base_field_name, format))) renamed_field_name,

或仅仅base_field_name作为字段的简单情况,Perl中的正则表达式是什么样的?

4 个答案:

答案 0 :(得分:11)

不要尝试编写正则表达式解析器(尽管perl regexes 可以处理这样的嵌套模式),使用SQL::Statement::Structure

答案 1 :(得分:2)

为什么不询问目标数据库本身如何解释查询?

在perl中,可以使用DBI来查询SQL查询的预处理表示。有时这是特定于数据库的:一些驱动程序(在perl DBD::命名空间下)支持其RDBMS的描述语句的想法,其方式类似于RDBMS的本机C或C ++ API。

但是,一般情况下可以这样做,因为DBI会将结果列的名称放在语句句柄属性NAME中。例如,以下内容很有可能在任何支持DBI的RDBMS上工作:

use strict;
use warnings;
use DBI;

use constant DSN => 'dbi:YouHaveNotToldUs:dbname=we_do_not_know';

my $dbh = DBI->connect(DSN, ..., { RaiseError => 1 });

my $sth;
while (<>) {
  next unless /^SELECT/i;   # SELECTs only, assume whole query on one line
  chomp;
  my $sql = /\bWHERE\b/i ? "$_ AND 1=0" : "$_ WHERE 1=0"; # XXX ugly!
  eval {
    $sth = $dbh->prepare($sql);  # some drivers don't know column names
    $sth->execute();             # until after a successful execute()
  };
  print $@, next if $@;  # oops, problem with that one
  print join(', ', @{$sth->{NAME}}), "\n";
}

XXX丑陋!位会尝试在SELECT上附加一个始终为false的条件,以便SQL引擎在execute()时不必执行任何实际操作。这是一种非常天真的方法 - /\bWHERE\b/i测试不再正确识别SQL WHERE子句,而不是简单的正则表达式正确解析SELECT字段名称 - 但它很可能有效。

答案 2 :(得分:1)

在我使用的办公室有点相关的问题:

my @SqlKeyWordList = qw/select from where .../; # (1)

my @Candidates =split(/\s/,$SqlSelectQuery);      # (2)

my %FieldHash;                                  # (3)
for my $Word (@Candidates)  { 
   next if grep($word,@SqlKeyWordList);
   $FieldHash($Word)++;
} 

评论:

  1. SqlKeyWordList包含可能在SQL语句中的所有SQL关键字(我们使用MySQL,有很多SQL拨号,选择/构建此列表是有效的,请看下面的评论!)。如果有人决定使用关键字作为字段名称,那么毕竟你需要一个正则表达式(更好地重构代码)。
  2. 将SQL语句拆分为单词列表,这是最棘手的部分,并且需要进行tweeking。现在它使用Perl概念“space”(= not in word)来分割。
    分割字段列表(选择a,b,c)和SQL的“from”部分可能在这里是建议的,取决于你的SQL语句。
  3. %MyFieldHash每个选择字段将包含一个条目(和gunk,直到您验证了SqlKeyWorkList和(2)中的正则表达式
  4. 当心

    • 此代码中没有任何内容无法在Python中完成。
    • 如果您可以影响所述SQL语句的创建,那么您的生活会更容易。 (例如,确保每个字段都写入评论)
    • 在这种解析方法中有太多可能/将会出错的事情,你真的应该完全回避这个问题,改变过程(从长远来看节省时间)。
    • 这是我们在办公室使用的正则表达式
       my @Candidates=split(/[\s
                      \(
                      \)
                      \+
                      \,
                      \*
                     \/
                      \-
                      \n
                      \
                      \=
                      \r
                     ]+/,$SqlSelectQuery
                   );
    
    

答案 3 :(得分:0)

如何将每一行拆分为术语(用换行符替换每个括号,逗号和空格),然后排序:

perl -ne's/[(), ]/\n/g; print' < textfile | sort -u

你最终会得到很多内容,例如:

fieldname1
fieldname1
formatstring
ltrim
rtrim
t_char