Это потому, что древовидная структура отличается для ключевых слов IN и сравнений. Например, сравнение включает в себя все выражение под ним в дереве.
Если вы используете parsed[0]._pprint_tree()
, вы можете видеть все, вложенное в узел сравнения:
|- 2 Comparison 'employ...'
| |- 0 Identifier 'employ...'
| | `- 0 Name 'employ...'
| |- 1 Whitespace ' '
| |- 2 Comparison '='
| |- 3 Whitespace ' '
| `- 4 Single ''Emplo...'
Однако, предложение NOT IN
представляет собой последовательность последовательных узлов:
|- 36 Identifier 'job_pr...'
| `- 0 Name 'job_pr...'
|- 37 Whitespace ' '
|- 38 Keyword 'NOT'
|- 39 Whitespace ' '
|- 40 Keyword 'IN'
|- 41 Whitespace ' '
|- 42 Parenthesis '('2099...'
| |- 0 Punctuation '('
| |- 1 IdentifierList ''20992...'
| | |- 0 Single "'20992'"
| | |- 1 Punctuation ','
| | |- 2 Whitespace ' '
| | |- 3 Single "'20993'"
| | |- 4 Punctuation ','
| | |- 5 Whitespace ' '
| | |- 6 Single "'20994'"
| | |- 7 Punctuation ','
| | |- 8 Whitespace ' '
| | |- 9 Single "'20995'"
| | |- 10 Punctuation ','
| | |- 11 Whitespace ' '
| | |- 12 Single "'20996'"
| | |- 13 Punctuation ','
| | |- 14 Whitespace ' '
| | `- 15 Single "'20997'"
| `- 2 Punctuation ')'
Лучше всего следить за идентификаторами, затем прыгать вперед и сохранять значение следующего узла в скобках. Хотя это не обрабатывает все возможные ситуации, оно обрабатывает ваш оператор SQL и возвращает значение job_profile_id
.
Вот мой модифицированный код:
import sqlparse
s = "select count(*) from users where employee_type = 'Employee' AND (employment_status = 'Active' OR employment_status = 'On Leave') AND (time_type='Full time' OR country_code <> 'US') AND hire_date < NOW() AND email_work IS NOT NULL AND LENGTH(email_work) > 0 AND NOT (job_profile_id IN ('8802 - Comm Ops - 1', '8801 - CityOps - 2', '10034', '10455', '21014', '21015', '21016', '21018', '21017', '21019') AND country_code = 'IE') AND job_profile_id NOT IN ('20992', '20993', '20994', '20995', '20996', '20997') AND country_code NOT IN ('CN', 'MO', 'SG', 'MY', 'TH', 'VN', 'MM', 'KH', 'PH', 'ID')"
parsed = sqlparse.parse(s)
where = parsed[0][-1]
sql_tokens = []
def get_tokens(where):
identifier = None
for i in where.tokens:
try:
name = i.get_real_name()
if name and isinstance(i, sqlparse.sql.Identifier):
identifier = i
elif identifier and isinstance(i, sqlparse.sql.Parenthesis):
sql_tokens.append({
'key': str(identifier),
'value': token.value
})
elif name:
identifier = None
# sql_tokens.append("{0} - {1} - {2}".format(str(i), str(name), i.value))
sql_tokens.append({
'key': str(name),
'value': u''.join(token.value for token in i.flatten()),
})
else:
get_tokens(i)
except Exception as e:
pass
get_tokens(where)
print sql_tokens