
Создатель
  
Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва
Репутация: нет Всего: 8
|
Пишу парсер для макросов для пользователей, чтобы использовать реляционную алгебру. SQL учить категорически отказались. Создал формат макросов и обработчик. Только проблема, когда надо задействовать несколько связанных таблиц. Хочу сделать, чтобы связанные таблицы указывались через запятую, а способ их связывания брался бы из внешних ключей. Задача: известны имена двух таблиц A и Б, известно, что Б - таблица подчинённая А (есть внешний ключ). Надо создать выражение на SQL, описывающее эту связь (INNER JOIN....). А дельше, просто приведу примеры макросов, как можно ещё извращаться. Пример макросов: | Код | %операция1 'ПРОДАЮ' %операция2 'СДАЮ' %операция3 'МЕНЯЮ' %код_базы 2
[LINKS INNER JOIN PAPKA ON LINKS.N_PAPKI=PAPKA.N_PAPKI]
ЕСЛИ 20 КОЛ-ВО vid_oper это %операция1 data_reg ранее сейчас data_opl не пусто id_base это 1
--------------------------
[PAPKA]
ЕСЛИ 30 vid_oper это %операция2 data_reg не ранее сейчас data_opl не пусто id_base это %код_базы
ИЗМЕНИТЬ data_obn это вчера
--------------------------
[PAPKA]
УДАЛИТЬ n_papki это %операция3
|
Пример обработчика: | Код | use DBI; use Data::Dumper; use locale;
BEGIN { %::CMD=( 'ЕСЛИ'=>'SELECT', 'ИЗМЕНИТЬ'=>'UPDATE', 'УДАЛИТЬ'=>'DELETE' ); %::SBST=( 'СЕГОДНЯ'=>'CURRENT_DATE', 'TODAY'=>'CURRENT_DATE', 'NOW'=>'CURRENT_TIMESTAMP', 'СЕЙЧАС'=>'CURRENT_TIMESTAMP', 'ВЧЕРА'=>'CURRENT_DATE-1', 'ЗАВТРА'=>'CURRENT_DATE+1' ); %::CMP=( '>'=>'>', 'БОЛЕЕ'=>'<', 'ПОЗЖЕ'=>'>', 'НЕ ПОЗЖЕ'=>'<=', 'НЕ БОЛЕЕ'=>'<=', '<'=>'<', 'МЕНЕЕ'=>'<', 'РАНЕЕ'=>'<', 'НЕ МЕНЕЕ'=>'>=', 'НЕ РАНЕЕ'=>'>=', 'ЭТО НЕ'=>'<>', '<>'=>'<>', '!='=>'<>', 'НЕ РАВНО'=>'<>', 'РАВНО'=>'=', '='=>'=', 'ЭТО'=>'=', '>='=>'>=', 'БОЛЕЕ ИЛИ РАВНО'=>'>=', '=<'=>'=<', 'МЕНЕЕ ИЛИ РАВНО'=>'<=', 'СОДЕРЖИТ'=>'CONTAINING', 'ТАМ ЕСТЬ'=>'CONTAINING', 'ТАМ НЕТ'=>'CONTAINING', 'НЕ СОДЕРЖИТ'=>'NOT CONTAINING', 'НАЧИНАЕТСЯ С'=>'STARTS WITH', 'НЕ НАЧИНАЕТСЯ С'=>'NOT STARTS WITH', 'ПУСТО'=>'IS NULL', 'НЕ ПУСТО'=>'IS NOT NULL' ); }
sub make { my($table, $where, $set, $select, $update, $delete, $part, $count)=( shift, shift, shift, shift, shift, shift, shift, shift ); $table=$table=~m{\s}?$table:'"'.$table.'"'; return 'DELETE FROM '.$table.(@$where?' WHERE '.join(' AND ', @$where):undef) if $delete; return 'UPDATE '.$table.' SET '.join(', ', @$set).(@$where?' WHERE '.join(' AND ', @$where):undef) if $update && @$set; return 'SELECT '.$part.' '.($count ? $count : '*').' FROM '.$table. (@$where?' WHERE '.join(' AND ', @$where):undef) } sub parse { my($macro, $table, @where, @set, $mode, $select, $update, $delete, $part, $count, @result, %vars)=shift; my$id_firm="ID_FIRM='010'"; push @where, $id_firm; open my$fh, '<'.$macro;binmode $fh; while(<$fh>) { if(/^\s*\%(\S+)\s+(.*?)\s*$/i) { $vars{+uc $1}=$2 } elsif(/^\s*\[\s*(.+?)\s*\]/) { if($table) { push @result, &make($table, \@where, \@set, $select, $update, $delete, $part, $count); undef $table; undef @where; push @where, $id_firm; undef @set; undef $select; undef $update; undef $part; undef $count; } $table=$1; } elsif(/^\s*(\w+)\s*( НЕ\s+СОДЕРЖИТ | НЕ\s+РАВНО | НЕ\s+ПУСТО | НЕ\s+БОЛЕЕ | НЕ\s+МЕНЕЕ | НЕ\s+РАНЕЕ | НЕ\s+ПОЗЖЕ | ЭТО\s+НЕ | МЕНЕЕ\s+ИЛИ\s+РАВНО | БОЛЕЕ\s+ИЛИ\s+РАВНО | НЕ\s+НАЧИНАЕТСЯ\s+С | НАЧИНАЕТСЯ\s+С | СОДЕРЖИТ | ТАМ\s+ЕСТЬ | ТАМ\s+НЕТ | РАВНО | ЭТО | ПУСТО | ПОЗЖЕ | РАНЕЕ | МЕНЕЕ | БОЛЕЕ | \= | \> | \=\s*\> | \=\s*\< | \<\s*\> | \< | \!\s*\= )\s*([^\r\n]*) /ix) { my$cmp=uc $2; my($fld, $str)=($1, $3); $cmp=~s{\s+}{ }gos; $cmp=~s{^\s+|\s+$}{}gos; $cmp=$::CMP{$cmp}; $str=~s{\%(.+?)\b}{ +exists $vars{+uc $1} ? $vars{+uc $1} : $& }geos; $str=~s{\b(СЕГОДНЯ|TODAY|NOW|СЕЙЧАС|ВЧЕРА|ЗАВТРА)\b}{ + exists $::SBST{+uc $1} ? $::SBST{+uc $1} : $1 }geios; push @{$mode?\@set:\@where}, join ' ', $fld, $cmp, $str } elsif(/^\s*ЕСЛИ\b\s*(?:(\d+))?\s*(КОЛ(?:ИЧЕСТ|\-)ВО)?\s*$/i) { $count=$2?' COUNT(*) ':undef; $part=' FIRST '.$1.' '; $select=1; $mode=undef; } elsif(/^\s*УД(?:АЛИТЬ)?\b/) { $delete=1; $mode=undef; } elsif(/^\s*ИЗМ(?:ЕНИТЬ)?\b/i) { $update=1; $mode=1; } } close $fh; +@result, &make($table, \@where, \@set, $select, $update, $delete, $part, $count) }
#my$dbh=DBI->connect('dbi:ODBC:dsn=DB', 'SYSDBA', 'masterkey'); #my$sth;
foreach(&parse('macro.ini')) { print $_, "\n"; # $sth=$dbh->prepare($_); # $sth->finish; }
#$dbh->disconnect;
|
|