繁体   English   中英

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

[英]How can I extract field names from SQL with Perl?

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

给定的select语句字段可能具有多个嵌套括号,例如:

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

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

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

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

在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丑陋! 有点尝试将始终为false的条件附加到SELECT上,以便当您execute()时,SQL引擎不必执行任何实际工作。 这是一种非常幼稚的方法- /\\bWHERE\\b/i测试无法正确地识别出SQL WHERE子句,而不是简单的正则表达式可以正确地解析出SELECT字段名称-但它可能会起作用。

在办公室中一个有点相关的问题中,我使用了:

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的“空间”概念(=不在单词中)进行拆分。
    拆分字段列表(选择a,b,c),SQL的“ from”部分在这里可能是适当的,具体取决于您的SQL语句。
  3. %MyFieldHash将在每个选择字段中包含一个条目(包括乱码,直到您在(2)中验证了SqlKeyWorkList和正则表达式为止

谨防

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

如何将每行分割成多个字词(用换行符替换每个括号,逗号和空格),然后进行排序:

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

您最终将获得很多内容,例如:

fieldname1
fieldname1
formatstring
ltrim
rtrim
t_char

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM