Как извлечь имена полей из SQL с помощью Perl? - PullRequest
0 голосов
/ 01 февраля 2010

У меня есть несколько операторов выбора в текстовом файле, и мне нужно извлечь имена полей из каждого запроса выбора. Это было бы легко, если бы в некоторых полях не использовались вложенные функции, такие как to_char() и т. Д.

С учетом полей оператора select, которые могут иметь несколько вложенных скобок, например:

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

Или простой случай base_field_name как поля, как бы выглядело регулярное выражение в Perl?

Ответы [ 4 ]

11 голосов
/ 01 февраля 2010

Не пытайтесь написать синтаксический анализатор регулярных выражений (хотя регулярные выражения perl могут обрабатывать подобные шаблоны), используйте SQL :: Statement :: Structure .

2 голосов
/ 01 февраля 2010

Почему бы не спросить саму целевую базу данных, как она будет интерпретировать запросы?

В Perl можно использовать DBI для запроса подготовленного представления запроса SQL. Иногда это зависит от базы данных: некоторые драйверы (в пространстве имен perl DBD::) поддерживают в своей СУБД идею , описывающую операторы способами, аналогичными нативному API С или С ++ СУБД.

Однако это может быть сделано в общем случае, поскольку DBI поместит имена столбцов результата в атрибут дескриптора оператора NAME. Следующие, например, имеют хорошие шансы работать на любой поддерживаемой DBI СУБД:

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, чтобы движок SQL не выполнял никакой реальной работы, когда вы execute(). Это очень наивный подход - этот тест /\bWHERE\b/i не более правильно идентифицирует предложение SQL WHERE, чем простые регулярные выражения, правильно анализирующие имена полей SELECT, - но он, вероятно, сработает.

1 голос
/ 01 февраля 2010

В какой-то связанной проблеме в офисе я использовал:

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 на список слов, это самая сложная часть, и она НЕОБХОДИМА для настройки. На данный момент в Perl используется понятие «пробел» (не в слове) для разделения.
    Разделение списка полей (выберите a, b, c) и часть SQL "from" может быть здесь рекомендуемой, зависит от ваших операторов SQL.
  3. % MyFieldHash будет содержать одну запись на каждое поле выбора (и ганк, пока вы не подтвердите свой SqlKeyWorkList и регулярное выражение в (2)

Осторожно

  • в этом коде нет ничего, что нельзя было бы сделать в Python.
  • ваша жизнь была бы намного проще, если бы вы могли влиять на создание указанных операторов SQL. (например, убедитесь, что каждое поле записано в комментарии)
  • Есть так много вещей, которые могут / будут идти не так в этом подходе анализа, вы действительно должны полностью обойти проблему, изменив процесс (экономит время в долгосрочной перспективе).
  • это регулярное выражение, которое мы используем в офисе
   my @Candidates=split(/[\s
                  \(
                  \)
                  \+
                  \,
                  \*
                 \/
                  \-
                  \n
                  \
                  \=
                  \r
                 ]+/,$SqlSelectQuery
               );

0 голосов
/ 01 февраля 2010

Как насчет разделения каждой строки на термины (замените каждую скобку, запятую и пробел на новую строку), а затем сортируйте:

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

Вы получите много контента, например:

fieldname1
fieldname1
formatstring
ltrim
rtrim
t_char
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...