2013-06-04 3 views
3

Я изучаю PyParsing в последние несколько недель. Я планирую использовать его для получения имен таблиц из операторов SQL. Я посмотрел http://pyparsing.wikispaces.com/file/view/simpleSQL.py. Но я намерен сохранить грамматику просто, потому что я не пытаюсь разобрать каждую часть выражения select, но я ищу только имена таблиц. Также довольно сложно определить полную грамматику для любой имеющейся в продаже современной базы данных, такой как Teradata.SQL-синтаксический анализ с использованием pyparsing

#!/usr/bin/env python 

from pyparsing import * 
import sys 

semicolon = Combine(Literal(';') + lineEnd) 
comma = Literal(',') 
lparen = Literal('(') 
rparen = Literal(')') 

# Keyword definition 
update_kw, volatile_kw, create_kw, table_kw, as_kw, from_kw, \ 
where_kw, join_kw, left_kw, right_kw, cross_kw, outer_kw, \ 
on_kw , insert_kw , into_kw= \ 
    map(lambda x: Keyword(x, caseless=True), \ 
     ['UPDATE', 'VOLATILE', 'CREATE', 'TABLE', 'AS', 'FROM', 
     'WHERE', 'JOIN' , 'LEFT', 'RIGHT' , \ 
     'CROSS', 'OUTER', 'ON', 'INSERT', 'INTO']) 

# Teradata SQL allows SELECT and well as SEL keyword 
select_kw = Keyword('SELECT', caseless=True) | Keyword('SEL' , caseless=True) 

# list of reserved keywords 
reserved_words = (update_kw | volatile_kw | create_kw | table_kw | as_kw | 
        select_kw | from_kw | where_kw | join_kw | 
        left_kw | right_kw | cross_kw | on_kw | insert_kw | 
        into_kw) 

# Identifier can be used as table or column names. They can't be reserved words 
ident = ~reserved_words + Word(alphas, alphanums + '_') 

# Recursive definition for table 
table = Forward() 
# simple table name can be identifer or qualified identifier e.g. schema.table 
simple_table = Combine(Optional(ident + Literal('.')) + ident) 
# table name can also a complete select statement used as table 
nested_table = lparen.suppress() + select_kw.suppress() + SkipTo(from_kw).suppress() + \ 
       from_kw.suppress() + table + rparen.suppress() 
# table can be simple table or nested table 
table << (nested_table | simple_table) 
# comma delimited list of tables 
table_list = delimitedList(table) 
# Building from clause only because table name(s) will always appears after that 
from_clause = from_kw.suppress() + table_list 


txt = """ 
SELECT p, (SELECT * FROM foo),e FROM a, d, (SELECT * FROM z), b 
""" 
for token, start, end in from_clause.scanString(txt): 
    print token 

вещь стоит здесь. Я использую «SkipTo (from_kw)», чтобы перепрыгнуть через список столбцов в инструкции SQL. Это прежде всего для того, чтобы избежать определения грамматики для списка столбцов, который может быть разделенным запятыми списком идентификаторов, многими именами функций, аналитическими функциями DW, а что нет. С помощью этой грамматики я могу разобрать инструкцию выше, а также любой уровень вложенности в списке столбцов или списка SELECT.

['foo'] 
['a', 'd', 'z', 'b'] 

Я перед проблемой, когда SELECT, имеет где положение:

nested_table = lparen.suppress() + select_kw.suppress() + SkipTo(from_kw).suppress() + \ 
       from_kw.suppress() + table + rparen.suppress() 

Когда ИНЕКЕ есть то же утверждение может выглядеть следующим образом: SELECT ... FROM a, d, (SELECT * FROM г WHERE (c1 = 1) и (c2 = 3)), р я думал об изменении "nested_table" определение:

nested_table = lparen.suppress() + select_kw.suppress() + SkipTo(from_kw).suppress() + \ 
       from_kw.suppress() + table + Optional(where_kw + SkipTo(rparen)) + rparen 

Но это не работает, так как он совпадает с правой Паре nthesis после "c = 1". Я хотел бы знать, как пропустить правую круглую скобку, которая соответствует левой скобке прямо перед «SELECT * FROM z ...». Я не знаю, как это сделать, используя PyParsing.

Также в другом примечании I искать советы - лучший способ получить имена таблиц из сложных вложенных SQL-запросов. Любая помощь действительно ценится.

Благодаря Abhijit

+0

Любая помощь от кого-либо? –

ответ

5

Учитывая, что вы также пытаются разобрать вложенными SELECT, х, я не думаю, что вы будете в состоянии избежать написания достаточно полный SQL-анализатор. К счастью, есть более полный пример на странице примеров википараций Pyparsing, select_parser.py. Надеюсь, это поможет вам продвинуться дальше.

+0

Пол, очень ценю ваше руководство. Излишне говорить, что я стал поклонником Pyparsing !! –

Смежные вопросы