Як перетворити результат SQL-запиту в структуру даних PANDAS?


116

Будь-яка допомога з цієї проблеми буде дуже вдячна.

Отже, я хочу запустити запит до своєї бази даних SQL і зберігати повернені дані як структуру даних Pandas.

Я додав код для запиту.

Я читаю документацію на Pandas, але у мене виникають проблеми з визначенням типу повернення мого запиту.

Я спробував роздрукувати результат запиту, але він не дає корисної інформації.

Дякую!!!!

from sqlalchemy import create_engine

engine2 = create_engine('mysql://THE DATABASE I AM ACCESSING')
connection2 = engine2.connect()
dataid = 1022
resoverall = connection2.execute("
  SELECT 
      sum(BLABLA) AS BLA,
      sum(BLABLABLA2) AS BLABLABLA2,
      sum(SOME_INT) AS SOME_INT,
      sum(SOME_INT2) AS SOME_INT2,
      100*sum(SOME_INT2)/sum(SOME_INT) AS ctr,
      sum(SOME_INT2)/sum(SOME_INT) AS cpc
   FROM daily_report_cooked
   WHERE campaign_id = '%s'", %dataid)

Тому я хотів би зрозуміти, що таке формат / тип даних моєї змінної "resoverall" і як це можна встановити за допомогою структури даних PANDAS.


В основному, що таке структура / тип змінної "resoverall" і як перетворити її в структуру даних Pandas.
користувач1613017

Панда звучить досить цікаво, я про це раніше не чув, але це питання ледь не має сенсу. Чи можете ви спробувати уточнити, що ви маєте на увазі під "не дає корисної інформації"?
тадман

1
Оскільки виконаний мною запит дає повернення, просто цікаво, як я маніпулюю цим поверненням і перетворюю його в структуру даних панди. Я дуже новачок у python, тому не маю багато знань, як, наприклад, те, що ми робимо в PHP, це просто зробити sql_fetch_array і у нас є "корисні" дані. =)
користувач1613017

Відповіді:


120

Ось найкоротший код, який виконає цю роботу:

from pandas import DataFrame
df = DataFrame(resoverall.fetchall())
df.columns = resoverall.keys()

Ви можете пофантазувати і проаналізувати типи, як у відповіді Павла.


1
Це працювало для мене на 1 000 000 записів, взятих із бази даних Oracle.
Erdem KAYA

8
df = DataFrame(cursor.fetchall())повертається ValueError: DataFrame constructor not properly called!, виявляється, що кортеж кортежів не прийнятний для конструктора DataFrame. Немає і .keys()курсору, ні в словнику, ні в режимі кортежу.
Mobigital

3
Зауважте лише, що метод ключів працюватиме лише з результатами, отриманими за допомогою sqlalchemy. Pyodbc використовує атрибут опису для стовпців.
Філіп

Чи може це працювати для баз даних Postgres? Я намагаюся отримати імена стовпців для результату фрейму даних з keys()функцією, але не можу змусити його працювати.
Боуен Лю

1
@BowenLiu Так, ви можете використовувати з psycopg2df.columns=[ x.name for x in recoverall.description ]
Gnudiff

136

Редакція: 2015 р

Як зазначалося нижче, зараз панди використовують SQLAlchemy як для читання з ( read_sql ), так і для вставки в ( to_sql ) базу даних. Наступне має працювати

import pandas as pd

df = pd.read_sql(sql, cnxn)

Попередня відповідь: Через mikebmassey з подібного питання

import pyodbc
import pandas.io.sql as psql

cnxn = pyodbc.connect(connection_info) 
cursor = cnxn.cursor()
sql = "SELECT * FROM TABLE"

df = psql.frame_query(sql, cnxn)
cnxn.close()

Здається, це найкращий спосіб зробити це, оскільки вам не потрібно вручну використовувати .keys (), щоб отримати індекс стовпців. Ймовірно, відповідь Даніеля була написана до існування цього методу. Ви також можете використовувати pandas.io.sql.read_frame ()
RobinL

1
@openwonk де реалізувати pd.read_sql()в фрагменті коду вище?
3kstc

Насправді, з моєї останньої відповіді, я досить багато використовував pyodbcі pandasразом. Додавання нової відповіді на прикладі, FYI.
openwonk

33

Якщо ви використовуєте ORM SQLAlchemy, а не мову вираження, ви можете виявити, що хочете перетворити об'єкт типу sqlalchemy.orm.query.Queryв кадр даних Pandas.

Найчистішим підходом є отримання згенерованого SQL з атрибута оператора запиту, а потім його виконання read_sql()методом pandas . Наприклад, починаючи з об'єкта Query під назвою query:

df = pd.read_sql(query.statement, query.session.bind)

5
Більш ефективним підходом є отримання оператора з sqlalchemy і дозволити пандам робити сам запит pandas.read_sql_query, переходячи query.statementдо нього. Дивіться цей відповідь: stackoverflow.com/a/29528804/1273938
LeoRochael

Дякую @LeoRochael! Я відредагував свою відповідь. Однозначно чистіше!
Натан Гулд

23

Редагувати 2014-09-30:

зараз панди мають read_sql функцію. Ви напевно хочете використовувати це замість цього.

Оригінальна відповідь:

Я не можу вам допомогти з SQLAlchemy - я завжди використовую pyodbc, MySQLdb або psychopg2 за потреби. Але при цьому функція настільки проста, як та, яка наведена нижче, відповідає моїм потребам:

import decimal

import pydobc
import numpy as np
import pandas

cnn, cur = myConnectToDBfunction()
cmd = "SELECT * FROM myTable"
cur.execute(cmd)
dataframe = __processCursor(cur, dataframe=True)

def __processCursor(cur, dataframe=False, index=None):
    '''
    Processes a database cursor with data on it into either
    a structured numpy array or a pandas dataframe.

    input:
    cur - a pyodbc cursor that has just received data
    dataframe - bool. if false, a numpy record array is returned
                if true, return a pandas dataframe
    index - list of column(s) to use as index in a pandas dataframe
    '''
    datatypes = []
    colinfo = cur.description
    for col in colinfo:
        if col[1] == unicode:
            datatypes.append((col[0], 'U%d' % col[3]))
        elif col[1] == str:
            datatypes.append((col[0], 'S%d' % col[3]))
        elif col[1] in [float, decimal.Decimal]:
            datatypes.append((col[0], 'f4'))
        elif col[1] == datetime.datetime:
            datatypes.append((col[0], 'O4'))
        elif col[1] == int:
            datatypes.append((col[0], 'i4'))

    data = []
    for row in cur:
        data.append(tuple(row))

    array = np.array(data, dtype=datatypes)
    if dataframe:
        output = pandas.DataFrame.from_records(array)

        if index is not None:
            output = output.set_index(index)

    else:
        output = array

    return output

Я думаю, вам потрібно імпортувати десяткові кудись вгорі?
joefromct

@joefromct Можливо, але ця відповідь настільки застаріла, що я дійсно повинен просто вразити всю справу і показати методи панд.
Пол H,

Це може бути Релевент для деяких ... причини я вивчав це з - за мій інше питання, використовуючи read_sql (одночасно) відбувся stackoverflow.com/questions/32847246 / ...
joefromct

Це стосується тих, хто не може використовувати SQLAlchemy, яка підтримує не всі бази даних.
кульгавий

@lamecicle дещо не згоден. IIRC, read_sqlвсе ще може приймати з'єднання, що не належать до SQLAlchemy, наприклад, pyodbc, psychopg2 тощо
Пол H,

16

Роз'єм MySQL

Для тих, хто працює з з'єднувачем mysql, ви можете використовувати цей код для початку. (Дякую @Daniel Velkov)

Використані реф.


import pandas as pd
import mysql.connector

# Setup MySQL connection
db = mysql.connector.connect(
    host="<IP>",              # your host, usually localhost
    user="<USER>",            # your username
    password="<PASS>",        # your password
    database="<DATABASE>"     # name of the data base
)   

# You must create a Cursor object. It will let you execute all the queries you need
cur = db.cursor()

# Use all the SQL you like
cur.execute("SELECT * FROM <TABLE>")

# Put it all to a data frame
sql_data = pd.DataFrame(cur.fetchall())
sql_data.columns = cur.column_names

# Close the session
db.close()

# Show the data
print(sql_data.head())

9

Ось код, який я використовую. Сподіваюся, це допомагає.

import pandas as pd
from sqlalchemy import create_engine

def getData():
  # Parameters
  ServerName = "my_server"
  Database = "my_db"
  UserPwd = "user:pwd"
  Driver = "driver=SQL Server Native Client 11.0"

  # Create the connection
  engine = create_engine('mssql+pyodbc://' + UserPwd + '@' + ServerName + '/' + Database + "?" + Driver)

  sql = "select * from mytable"
  df = pd.read_sql(sql, engine)
  return df

df2 = getData()
print(df2)

9

Це коротка і чітка відповідь на вашу проблему:

from __future__ import print_function
import MySQLdb
import numpy as np
import pandas as pd
import xlrd

# Connecting to MySQL Database
connection = MySQLdb.connect(
             host="hostname",
             port=0000,
             user="userID",
             passwd="password",
             db="table_documents",
             charset='utf8'
           )
print(connection)
#getting data from database into a dataframe
sql_for_df = 'select * from tabledata'
df_from_database = pd.read_sql(sql_for_df , connection)

8

1. Використання MySQL-connector-python

# pip install mysql-connector-python

import mysql.connector
import pandas as pd

mydb = mysql.connector.connect(
    host = 'host',
    user = 'username',
    passwd = 'pass',
    database = 'db_name'
)
query = 'select * from table_name'
df = pd.read_sql(query, con = mydb)
print(df)

2. Використання SQLAlchemy

# pip install pymysql
# pip install sqlalchemy

import pandas as pd
import sqlalchemy

engine = sqlalchemy.create_engine('mysql+pymysql://username:password@localhost:3306/db_name')

query = '''
select * from table_name
'''
df = pd.read_sql_query(query, engine)
print(df)

проста і чудова відповідь!
Лукас Аймаретто

5

Як і Натан, я часто хочу скинути результати sqlalchemy або sqlsoup Query у кадр даних Pandas. Моє власне рішення для цього:

query = session.query(tbl.Field1, tbl.Field2)
DataFrame(query.all(), columns=[column['name'] for column in query.column_descriptions])

1
Якщо у вас є об’єкт запиту. Ефективніше отримати оператор з sqlalchemy і дозволити пандам робити сам запит pandas.read_sql_query, переходячи query.statementдо нього. Дивіться цей відповідь: stackoverflow.com/a/29528804/1273938
LeoRochael

4

resoverallє об'єктом sqlalchemy ResultProxy. Детальніше про це можна прочитати в документах sqlalchemy , останній пояснює основне використання роботи з двигунами та з'єднаннями. Тут важливим resoverallє диктування.

Pandas любить диктувати подібні об'єкти для створення своїх структур даних, дивіться онлайн-документи

Удачі з sqlalchemy та пандами.


4

Просто використовуйте pandasта pyodbcразом. Вам доведеться змінити рядок з'єднання ( connstr) відповідно до специфікацій вашої бази даних.

import pyodbc
import pandas as pd

# MSSQL Connection String Example
connstr = "Server=myServerAddress;Database=myDB;User Id=myUsername;Password=myPass;"

# Query Database and Create DataFrame Using Results
df = pd.read_sql("select * from myTable", pyodbc.connect(connstr))

Я використовував pyodbcдекілька корпоративних баз даних (наприклад, SQL Server, MySQL, MariaDB, IBM).


Як записати цей фрейм даних знову в MSSQL за допомогою Pyodbc? Інше, ніж використання sqlalchemy
Ramsey

Використовуйте to_sqlметод на DataFrameоб’єкті. Цей метод за замовчуванням відповідає SQLite, тому вам доведеться явно передавати йому об’єкт, що вказує на базу даних MSSQL. Див. Документи .
openwonk

Я спробував нижче, і у мене є близько 200 К рядків з 13 стовпцями. Він також не завершений через 15 хвилин. Будь-які ідеї? df.to_sql ('ім'я таблиці', двигун, схема = 'схема схеми', if_exists = 'додати', індекс = помилково)
Ramsey

Це здається повільним ... Мені, напевно, потрібно було б бачити весь код у дії, вибачте. Я хотів би pandasбути більш оптимізованим для легкої роботи ETL, але на жаль ...
openwonk

3

Це питання давнє, але я хотів додати свої два центи. Я читаю питання як "Я хочу запустити запит до своєї [моєї] бази даних SQL і зберігати повернені дані як структуру даних Pandas [DataFrame]."

З коду, схоже, ви маєте на увазі базу даних mysql і припускаєте, що ви маєте на увазі панди DataFrame.

import MySQLdb as mdb
import pandas.io.sql as sql
from pandas import *

conn = mdb.connect('<server>','<user>','<pass>','<db>');
df = sql.read_frame('<query>', conn)

Наприклад,

conn = mdb.connect('localhost','myname','mypass','testdb');
df = sql.read_frame('select * from testTable', conn)

Це імпортує всі рядки testTable у DataFrame.


1

Ось моя. Про всяк випадок, якщо ви використовуєте "pymysql":

import pymysql
from pandas import DataFrame

host   = 'localhost'
port   = 3306
user   = 'yourUserName'
passwd = 'yourPassword'
db     = 'yourDatabase'

cnx    = pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=db)
cur    = cnx.cursor()

query  = """ SELECT * FROM yourTable LIMIT 10"""
cur.execute(query)

field_names = [i[0] for i in cur.description]
get_data = [xx for xx in cur]

cur.close()
cnx.close()

df = DataFrame(get_data)
df.columns = field_names

1

pandas.io.sql.write_frame ВИЗНАЧЕНО. https://pandas.pydata.org/pandas-docs/version/0.15.2/generated/pandas.io.sql.write_frame.html

Слід змінити, щоб використовувати pandas.DataFrame.to_sql https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html

Є ще одне рішення. PYODBC для Pandas - DataFrame не працює - Форма переданих значень (x, y), індекси означають (w, z)

Станом на Pandas 0,12 (я вважаю) ви можете:

import pandas
import pyodbc

sql = 'select * from table'
cnn = pyodbc.connect(...)

data = pandas.read_sql(sql, cnn)

До 0,12 ви могли:

import pandas
from pandas.io.sql import read_frame
import pyodbc

sql = 'select * from table'
cnn = pyodbc.connect(...)

data = read_frame(sql, cnn)

Це далеко найпростіший спосіб
Вільмер Енао

0

Давно від останнього допису, але, можливо, це комусь допомагає ...

Короткий шлях, ніж Павло Н:

my_dic = session.query(query.all())
my_df = pandas.DataFrame.from_dict(my_dic)

0

найкращий спосіб я це роблю

db.execute(query) where db=db_class() #database class
    mydata=[x for x in db.fetchall()]
    df=pd.DataFrame(data=mydata)

0

Якщо типом результату є ResultSet , попередньо слід перетворити його у словник. Тоді стовпці DataFrame збиратимуться автоматично.

Це працює на моєму випадку:

df = pd.DataFrame([dict(r) for r in resoverall])
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.