Bagaimana cara mengubah hasil SQL Query menjadi PANDAS Data Structure?

116

Bantuan apa pun tentang masalah ini akan sangat dihargai.

Jadi pada dasarnya saya ingin menjalankan kueri ke database SQL saya dan menyimpan data yang dikembalikan sebagai struktur data Pandas.

Saya telah melampirkan kode untuk kueri.

Saya membaca dokumentasi tentang Pandas, tetapi saya memiliki masalah untuk mengidentifikasi jenis kembalian kueri saya.

Saya mencoba mencetak hasil kueri, tetapi tidak memberikan informasi yang berguna.

Terima kasih!!!!

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)

Jadi saya agak ingin memahami apa format / tipe data variabel saya "resoverall" dan bagaimana menaruhnya dengan struktur data PANDAS.

pengguna1613017
sumber
Pada dasarnya, apa itu struktur / jenis variabel "resoverall" dan bagaimana mengubahnya menjadi struktur data Pandas.
pengguna1613017
Panda terdengar cukup menarik, saya belum pernah mendengarnya sebelumnya, tetapi pertanyaan ini hampir tidak masuk akal. Dapatkah Anda mencoba dan menjelaskan apa yang Anda maksud dengan "tidak memberikan informasi yang berguna"?
tadman
1
Karena kueri yang telah saya eksekusi memberikan keuntungan, hanya bertanya-tanya bagaimana saya harus memanipulasi pengembalian ini dan membuatnya menjadi struktur data panda. Saya sangat baru mengenal python dan karena itu tidak memiliki banyak pengetahuan, seperti yang kami lakukan di PHP hanya untuk melakukan sql_fetch_array dan kami memiliki data yang "dapat digunakan". =)
user1613017

Jawaban:

120

Berikut kode terpendek yang akan melakukan pekerjaan itu:

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

Anda bisa lebih menarik dan mengurai jenisnya seperti dalam jawaban Paul.

Daniel Velkov
sumber
1
Ini berhasil bagi saya untuk 1.000.000 catatan yang diambil dari database Oracle.
Erdem KAYA
8
df = DataFrame(cursor.fetchall())mengembalikan ValueError: DataFrame constructor not properly called!, tampak bahwa tupel tupel tidak dapat diterima untuk konstruktor DataFrame. Juga tidak ada .keys()kursor baik dalam kamus atau mode tupel.
Mobigital
3
Perhatikan saja bahwa metode kunci hanya akan berfungsi dengan hasil yang diperoleh menggunakan sqlalchemy. Pyodbc menggunakan atribut deskripsi untuk kolom.
Filip
Bisakah ini berfungsi untuk database Postgres? Saya mencoba untuk mendapatkan nama kolom untuk dataframe hasil dengan keys()fungsi tetapi tidak bisa berfungsi.
Bowen Liu
1
@BowenLiu Ya, Anda dapat menggunakan dengan psycopg2df.columns=[ x.name for x in recoverall.description ]
Gnudiff
137

Edit: Maret 2015

Seperti disebutkan di bawah ini, panda sekarang menggunakan SQLAlchemy untuk membaca dari ( read_sql ) dan memasukkan ke ( to_sql ) database. Berikut ini seharusnya bekerja

import pandas as pd

df = pd.read_sql(sql, cnxn)

Jawaban sebelumnya: Melalui mikebmassey dari pertanyaan serupa

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()
jenggot
sumber
Ini tampaknya cara terbaik untuk melakukannya, karena Anda tidak perlu menggunakan .keys () secara manual untuk mendapatkan indeks kolom. Mungkin jawaban Daniel ditulis sebelum metode ini ada. Anda juga dapat menggunakan pandas.io.sql.read_frame ()
RobinL
1
@openwonk di mana akan diimplementasikan pd.read_sql()dalam potongan kode di atas?
3kstc
Sebenarnya, sejak tanggapan terakhir saya, saya sudah cukup sering menggunakan pyodbcdan pandasbersama. Menambahkan jawaban baru dengan contoh FYI.
openwonk
33

Jika Anda menggunakan ORM SQLAlchemy daripada bahasa ekspresi, Anda mungkin ingin mengonversi objek berjenis sqlalchemy.orm.query.Query menjadi bingkai data Pandas.

Pendekatan terbersih adalah mendapatkan SQL yang dihasilkan dari atribut pernyataan kueri, dan kemudian menjalankannya dengan read_sql()metode pandas . Misalnya, dimulai dengan objek Query yang disebut query:

df = pd.read_sql(query.statement, query.session.bind)
Nathan Gould
sumber
5
Pendekatan yang lebih efisien adalah mendapatkan pernyataan dari sqlalchemy dan membiarkan panda melakukan kueri itu sendiri pandas.read_sql_query, meneruskannya query.statement. Lihat jawaban ini: stackoverflow.com/a/29528804/1273938
LeoRochael
Terima kasih @LeoRochael! Saya mengedit jawaban saya. Jelas lebih bersih!
Nathan Gould
23

Sunting 2014-09-30:

panda kini memiliki read_sqlfungsi. Anda pasti ingin menggunakannya.

Jawaban asli:

Saya tidak dapat membantu Anda dengan SQLAlchemy - Saya selalu menggunakan pyodbc, MySQLdb, atau psychopg2 sesuai kebutuhan. Namun saat melakukannya, fungsi sesederhana di bawah ini cenderung sesuai dengan kebutuhan saya:

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
Paul H.
sumber
Saya pikir Anda perlu mengimpor desimal di suatu tempat di atas?
joefromct
@joefromct Mungkin, tapi jawaban ini sangat usang saya benar-benar harus menyerang semuanya dan menunjukkan metode panda.
Paul H
Mungkin relevan untuk beberapa ... alasan saya mempelajari ini adalah karena masalah saya yang lain, menggunakan read_sql () di sini stackoverflow.com/questions/32847246/…
joefromct
Ini relevan bagi mereka yang tidak dapat menggunakan SQLAlchemy yang tidak mendukung semua database.
lamecicle
@ lumut agak tidak setuju. IIRC, read_sqlmasih dapat menerima koneksi non-SQLAlchemy melalui misalnya, pyodbc, psychopg2, dll
Paul H
16

Konektor MySQL

Bagi mereka yang bekerja dengan konektor mysql, Anda dapat menggunakan kode ini sebagai permulaan. (Terima kasih kepada @Daniel Velkov)

Referensi yang digunakan:


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())
Thomas Devoogdt
sumber
9

Ini kode yang saya gunakan. Semoga ini membantu.

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)
Murali Bala
sumber
9

Ini adalah jawaban singkat dan jelas untuk masalah Anda:

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)
DeshDeep Singh
sumber
9

1. Menggunakan 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. Menggunakan 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)
Lintang Wisesa
sumber
jawaban sederhana dan bagus!
Lucas Aimaretto
5

Seperti Nathan, saya sering ingin membuang hasil dari sqlalchemy atau sqlsoup Query ke dalam bingkai data Pandas. Solusi saya sendiri untuk ini adalah:

query = session.query(tbl.Field1, tbl.Field2)
DataFrame(query.all(), columns=[column['name'] for column in query.column_descriptions])
Janak Mayer
sumber
1
Jika Anda memiliki objek kueri. Lebih efisien untuk mendapatkan pernyataan dari sqlalchemy dan membiarkan panda melakukan kueri itu sendiri pandas.read_sql_query, meneruskannya query.statement. Lihat jawaban ini: stackoverflow.com/a/29528804/1273938
LeoRochael
4

resoveralladalah objek ResultProxy sqlalchemy. Anda dapat membaca lebih lanjut tentang ini di dokumen sqlalchemy , yang terakhir menjelaskan penggunaan dasar bekerja dengan Mesin dan Koneksi. Penting di sini adalah resoverallseperti diktik.

Panda menyukai dikt seperti objek untuk membuat struktur datanya, lihat dokumen online

Semoga berhasil dengan sqlalchemy dan panda.

Wouter Overmeire
sumber
4

Cukup gunakan pandasdan pyodbcbersama - sama. Anda harus mengubah string koneksi Anda ( connstr) sesuai dengan spesifikasi database Anda.

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))

Saya telah menggunakan pyodbcbeberapa database perusahaan (misalnya SQL Server, MySQL, MariaDB, IBM).

openwonk
sumber
Bagaimana cara menulis dataframe ini kembali ke MSSQL menggunakan Pyodbc? Selain menggunakan sqlalchemy
Ramsey
Gunakan to_sqlmetode pada DataFrameobjek. Metode tersebut secara default menggunakan SQLite, jadi Anda harus secara eksplisit memberikan objek yang mengarah ke database MSSQL. Lihat dokumen .
buka wonk
Saya mencoba yang di bawah ini dan saya memiliki sekitar 200K baris dengan 13 kolom. Itu juga tidak selesai setelah 15 menit. Ada ide? df.to_sql ('tablename', engine, schema = 'schemaname', if_exists = 'append', index = False)
Ramsey
Sepertinya lambat ... Saya mungkin perlu melihat seluruh kode beraksi, maaf. Saya berharap pandaslebih dioptimalkan untuk pekerjaan ETL ringan, tapi sayangnya ...
openwonk
3

Pertanyaan ini sudah lama, tapi saya ingin menambahkan dua sen saya. Saya membaca pertanyaan sebagai "Saya ingin menjalankan kueri ke database SQL [saya] dan menyimpan data yang dikembalikan sebagai struktur data Pandas [DataFrame]."

Dari kode sepertinya yang Anda maksud adalah database mysql dan menganggap yang Anda maksud pandas 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)

Sebagai contoh,

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

Ini akan mengimpor semua baris testTable ke dalam DataFrame.

BubbleGuppies
sumber
1

Ini milikku. Untuk berjaga-jaga jika Anda menggunakan "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
kennyut
sumber
1

pandas.io.sql.write_frame TIDAK DIGUNAKAN LAGI. https://pandas.pydata.org/pandas-docs/version/0.15.2/generated/pandas.io.sql.write_frame.html

Harus berubah menggunakan pandas.DataFrame.to_sql https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html

Ada solusi lain. PYODBC ke Pandas - DataFrame tidak berfungsi - Bentuk nilai yang diteruskan adalah (x, y), indeks menyiratkan (w, z)

Mulai Pandas 0.12 (saya yakin) Anda dapat melakukan:

import pandas
import pyodbc

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

data = pandas.read_sql(sql, cnn)

Sebelum 0.12, Anda dapat melakukan:

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

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

data = read_frame(sql, cnn)
江明哲
sumber
Sejauh ini adalah cara termudah
Wilmer E. Henao
0

Lama dari posting terakhir tapi mungkin itu membantu seseorang ...

Jalan pintas dari Paul H:

my_dic = session.query(query.all())
my_df = pandas.DataFrame.from_dict(my_dic)
Antonio Fernandez
sumber
0

cara terbaik saya melakukan ini

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

Jika tipe hasil adalah ResultSet , Anda harus mengubahnya menjadi kamus terlebih dahulu. Kemudian kolom DataFrame akan dikumpulkan secara otomatis.

Ini berfungsi pada kasus saya:

df = pd.DataFrame([dict(r) for r in resoverall])
tanza9
sumber