Выполнить файл SQL, вернуть результаты в виде Pandas DataFrame

У меня есть сложный запрос SQL Server, который я хотел бы выполнить из Python и вернуть результаты в виде Pandas DataFrame.

Моя база данных доступна только для чтения, поэтому у меня не так много вариантов, как говорят другие ответы, для создания менее сложных запросов.

Этот ответ был полезен, но я продолжаю получать TypeError: 'NoneType' object is not iterable

Пример SQL

Это не настоящий запрос - просто чтобы продемонстрировать, что у меня есть временные таблицы. Использование глобальных временных таблиц, поскольку мои запросы ранее не выполнялись с использованием локальных временных таблиц: См. этот вопрос

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

IF OBJECT_ID('tempdb..##temptable') IS NOT NULL DROP TABLE ##temptable
IF OBJECT_ID('tempdb..##results') IS NOT NULL DROP TABLE ##results

DECLARE @closing_period int = 0, @starting_period int = 0

Select col1, col2, col3 into ##temptable from readonlytables

Select * into ##results from ##temptable

Select * from ##results

Выполнить запрос с помощью pyodbc и pandas

conn = pyodbc.connect('db connection details')

sql = open('myquery.sql', 'r')
df = read_sql_query(sql.read(), conn)
sql.close()
conn.close()

Результаты — полная трассировка стека

ypeError                                 Traceback (most recent call last)
<ipython-input-38-4fcfe4123667> in <module>
      5 
      6 sql = open('sql/month_end_close_hp.sql', 'r')
----> 7 df = pd.read_sql_query(sql.read(), conn)
      8 #sql.close()
      9 

C:\ProgramData\Anaconda3\lib\site-packages\pandas\io\sql.py in read_sql_query(sql, con, index_col, coerce_float, params, parse_dates, chunksize)
    330         coerce_float=coerce_float,
    331         parse_dates=parse_dates,
--> 332         chunksize=chunksize,
    333     )
    334 

C:\ProgramData\Anaconda3\lib\site-packages\pandas\io\sql.py in read_query(self, sql, index_col, coerce_float, params, parse_dates, chunksize)
   1632         args = _convert_params(sql, params)
   1633         cursor = self.execute(*args)
-> 1634         columns = [col_desc[0] for col_desc in cursor.description]
   1635 
   1636         if chunksize is not None:

TypeError: 'NoneType' object is not iterable

Когда я запускаю запрос в своей базе данных, я получаю ожидаемые результаты. Если я передам запрос в виде строки, я также получу ожидаемые результаты:

Запрос как строка

conn = pyodbc.connect('db connection details')

sql = '''
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

IF OBJECT_ID('tempdb..##temptable') IS NOT NULL DROP TABLE ##temptable
IF OBJECT_ID('tempdb..##results') IS NOT NULL DROP TABLE ##results

DECLARE @closing_period int = 0, @starting_period int = 0

Select col1, col2, col3 into ##temptable from readonlytables

Select * into ##results from ##temptable

Select * from ##results
'''

df = read_sql(sql, conn)

conn.close()

Я думаю, это может иметь какое-то отношение к одинарным кавычкам внутри моего запроса?


person terrah27    schedule 18.08.2020    source источник
comment
Из интересного, чего Select * into ##results from ##temptable нужно добиться, кроме дублирования данных? И почему глобальные временные таблицы?   -  person Larnu    schedule 18.08.2020
comment
Вы можете опубликовать полную трассировку стека?   -  person Umar.H    schedule 18.08.2020
comment
После sql = open('myquery.sql', 'r') попробуйте df = read_sql_query(sql.read(), conn)   -  person Gord Thompson    schedule 18.08.2020
comment
@Larnu - я пытаюсь привести примеры того, что находится в моем запросе, фактически не публикуя сам запрос. Локальные временные таблицы не работали, когда я передавал запросы в виде строк, поэтому я перешел на глобальные (согласно этому ответу)[stackoverflow.com/questions/37863125/   -  person terrah27    schedule 18.08.2020
comment
@Manakin Добавлена ​​полная трассировка стека   -  person terrah27    schedule 18.08.2020
comment
@GordThompson Спасибо, что уловили это - у меня было в моем коде, но я не указал в вопросе. К сожалению, это не решает проблему.   -  person terrah27    schedule 18.08.2020
comment
Строка 7 в трассировке стека не соответствует коду примера. read() по-прежнему отсутствует.   -  person Gord Thompson    schedule 18.08.2020
comment
Я не могу воспроизвести вашу проблему. Этот код отлично работает для меня.   -  person Gord Thompson    schedule 19.08.2020


Ответы (1)


Я заработал.

Мне пришлось использовать глобальные переменные, заменив @ на @@. Я смог заставить запрос работать, как ожидалось.

DECLARE @@closing_period int = 0, @@starting_period int = 0

Обновление: мой драйвер ODBC сильно устарел — после обновления до последней версии мне больше не требовались глобальные временные таблицы или переменные, и запрос выполнялся значительно быстрее.

person terrah27    schedule 21.08.2020