Làm thế nào để chuyển đổi kết quả Truy vấn SQL sang Cấu trúc Dữ liệu PANDAS?


116

Bất kỳ trợ giúp nào về vấn đề này sẽ được đánh giá rất cao.

Vì vậy, về cơ bản tôi muốn chạy một truy vấn đến cơ sở dữ liệu SQL của mình và lưu trữ dữ liệu trả về dưới dạng cấu trúc dữ liệu Pandas.

Tôi đã đính kèm mã cho truy vấn.

Tôi đang đọc tài liệu về Pandas, nhưng tôi gặp sự cố khi xác định loại trả về của truy vấn của mình.

Tôi đã cố gắng in kết quả truy vấn, nhưng nó không cung cấp bất kỳ thông tin hữu ích nào.

Cảm ơn!!!!

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)

Vì vậy, tôi muốn hiểu định dạng / kiểu dữ liệu của biến "cộng hưởng" của tôi là gì và cách đặt nó với cấu trúc dữ liệu PANDAS.


Về cơ bản, cấu trúc / loại biến "cộng hưởng" là gì và cách chuyển đổi nó thành cấu trúc dữ liệu Pandas.
user1613017

Gấu trúc nghe có vẻ khá thú vị, tôi chưa từng nghe về nó trước đây, nhưng câu hỏi này hầu như không có ý nghĩa gì. Bạn có thể thử và làm rõ ý của bạn khi "không cung cấp bất kỳ thông tin hữu ích nào" không?
tadman

1
Bởi vì truy vấn tôi đã thực hiện trả về một trả về, tôi chỉ tự hỏi làm cách nào để thao tác với trả về này và biến nó thành cấu trúc dữ liệu gấu trúc. Tôi rất mới với python và do đó không có nhiều kiến ​​thức, giống như những gì chúng tôi làm trong PHP chỉ là thực hiện một sql_fetch_array và chúng tôi có dữ liệu "có thể sử dụng được". =)
user1613017

Câu trả lời:


120

Đây là mã ngắn nhất sẽ thực hiện công việc:

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

Bạn có thể tìm hiểu kỹ hơn và phân tích các kiểu như trong câu trả lời của Paul.


1
Điều này đã làm việc cho tôi cho 1.000.000 bản ghi từ cơ sở dữ liệu Oracle.
Erdem KAYA

8
df = DataFrame(cursor.fetchall())trả về ValueError: DataFrame constructor not properly called!, có vẻ như bộ giá trị không được chấp nhận đối với phương thức khởi tạo DataFrame. Cũng không có .keys()trên con trỏ ở chế độ từ điển hoặc tuple.
Mobigital

3
Chỉ cần lưu ý rằng phương pháp khóa sẽ chỉ hoạt động với kết quả thu được bằng cách sử dụng sqlalchemy. Pyodbc sử dụng thuộc tính mô tả cho các cột.
Filip

Điều này có thể hoạt động cho cơ sở dữ liệu Postgres không? Tôi đang cố gắng lấy tên cột cho khung dữ liệu kết quả bằng keys()hàm nhưng không thể làm cho nó hoạt động.
Bowen Liu

1
@BowenLiu Có, bạn có thể sử dụng với psycopg2df.columns=[ x.name for x in recoverall.description ]
Gnudiff

136

Chỉnh sửa: Tháng 3 năm 2015

Như đã lưu ý bên dưới, gấu trúc hiện sử dụng SQLAlchemy để đọc từ ( read_sql ) và chèn vào ( to_sql ) cơ sở dữ liệu. Những điều sau đây sẽ hoạt động

import pandas as pd

df = pd.read_sql(sql, cnxn)

Câu trả lời trước: Qua mikebmassey từ một câu hỏi tương tự

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

Đây có vẻ là cách tốt nhất để làm điều đó, vì bạn không cần phải sử dụng thủ công .keys () để lấy chỉ mục cột. Có lẽ câu trả lời của Daniel đã được viết trước khi phương pháp này tồn tại. Bạn cũng có thể sử dụng pandas.io.sql.read_frame ()
RobinL

1
@openwonk sẽ triển khai pd.read_sql()ở đâu trong đoạn mã trên?
3kstc

Trên thực tế, kể từ lần trả lời cuối cùng của tôi, tôi đã sử dụng pyodbcpandascùng nhau khá nhiều. Thêm câu trả lời mới với ví dụ, FYI.
openwonk

33

Nếu bạn đang sử dụng ORM của SQLAlchemy thay vì ngôn ngữ biểu thức, bạn có thể thấy mình muốn chuyển đổi một đối tượng kiểu sqlalchemy.orm.query.Querythành khung dữ liệu Pandas.

Cách tiếp cận rõ ràng nhất là lấy SQL được tạo từ thuộc tính câu lệnh của truy vấn, sau đó thực thi nó với read_sql() phương thức . Ví dụ: bắt đầu với một đối tượng Truy vấn được gọi là query:

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

5
Một cách tiếp cận hiệu quả hơn là lấy câu lệnh từ sqlalchemy và để gấu trúc tự thực hiện truy vấn với nó pandas.read_sql_query, chuyển query.statementtới nó. Xem câu trả lời này: stackoverflow.com/a/29528804/1273938
LeoRochael

Cảm ơn @LeoRochael! Tôi đã chỉnh sửa câu trả lời của mình. Chắc chắn là sạch hơn!
Nathan Gould

23

Chỉnh sửa 2014-09-30:

gấu trúc bây giờ có một read_sqlchức năng. Bạn chắc chắn muốn sử dụng nó thay thế.

Câu trả lời ban đầu:

Tôi không thể giúp bạn với SQLAlchemy - Tôi luôn sử dụng pyodbc, MySQLdb hoặc psychopg2 nếu cần. Nhưng khi làm như vậy, một hàm đơn giản như hàm dưới đây có xu hướng phù hợp với nhu cầu của tôi:

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

Tôi nghĩ bạn cần nhập số thập phân ở đâu đó lên trên cùng?
joefromct

@joefromct Có lẽ, nhưng câu trả lời này quá lỗi thời, tôi thực sự chỉ nên đánh giá toàn bộ vấn đề và hiển thị các phương pháp của gấu trúc.
Paul H

Nó có thể có liên quan đối với một số lý do ... tôi đã nghiên cứu này là do vấn đề khác của tôi, sử dụng read_sql () ở đây stackoverflow.com/questions/32847246/...
joefromct

Nó phù hợp cho những người không thể sử dụng SQLAlchemy không hỗ trợ tất cả các cơ sở dữ liệu.
lamecicle

@lamecicle hơi không đồng ý. IIRC, read_sqlvẫn có thể chấp nhận các kết nối không phải SQLAlchemy thông qua ví dụ: pyodbc, psychopg2, v.v.
Paul H

16

Trình kết nối MySQL

Đối với những người hoạt động với trình kết nối mysql, bạn có thể sử dụng mã này để bắt đầu. (Cảm ơn @Daniel Velkov)

Giới thiệu đã sử dụng:


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

Đây là mã tôi sử dụng. Hi vọng điêu nay co ich.

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

Đây là một câu trả lời ngắn gọn và rõ ràng cho vấn đề của bạn:

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. Sử dụng 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. Sử dụng 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)

câu trả lời đơn giản và tuyệt vời!
Lucas Aimaretto

5

Giống như Nathan, tôi thường muốn kết xuất kết quả của Truy vấn sqlalchemy hoặc sqlsoup vào khung dữ liệu Pandas. Giải pháp của riêng tôi cho điều này là:

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

1
Nếu bạn có một đối tượng truy vấn. Sẽ hiệu quả hơn khi lấy câu lệnh từ sqlalchemy và để gấu trúc tự thực hiện truy vấn với nó pandas.read_sql_query, chuyển query.statementtới nó. Xem câu trả lời này: stackoverflow.com/a/29528804/1273938
LeoRochael

4

resoveralllà một đối tượng sqlalchemy ResultProxy. Bạn có thể đọc thêm về nó trong tài liệu sqlalchemy , phần sau giải thích cách sử dụng cơ bản để làm việc với Công cụ và Kết nối. Quan trọng ở đây resoveralllà dict như thế nào.

Gấu trúc thích các đối tượng dict like để tạo cấu trúc dữ liệu của nó, hãy xem tài liệu trực tuyến

Chúc may mắn với sqlalchemy và gấu trúc.


4

Đơn giản chỉ cần sử dụng pandaspyodbccùng nhau. Bạn sẽ phải sửa đổi chuỗi kết nối của mình ( connstr) theo thông số cơ sở dữ liệu của bạn.

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

Tôi đã sử dụng pyodbcvới một số cơ sở dữ liệu doanh nghiệp (ví dụ: SQL Server, MySQL, MariaDB, IBM).


Làm cách nào để ghi lại khung dữ liệu này trở lại MSSQL bằng Pyodbc? Otherthan sử dụng SQLAlchemy
Ramsey

Sử dụng to_sqlphương thức trên DataFrameđối tượng. Phương thức đó mặc định là SQLite, vì vậy bạn phải chuyển nó một cách rõ ràng một đối tượng trỏ đến cơ sở dữ liệu MSSQL. Xem tài liệu .
openwonk

Tôi đã thử cái dưới đây và tôi có khoảng 200 nghìn hàng với 13 cột. Nó cũng không được hoàn thành sau 15 phút. Có ý kiến ​​gì không? df.to_sql ('tablename', engine, schema = 'schemaname', if_exists = 'append', index = False)
Ramsey

Điều đó có vẻ chậm ... Tôi có lẽ sẽ cần phải xem toàn bộ mã đang hoạt động, xin lỗi. Tôi ước gì pandasđược tối ưu hóa hơn cho công việc ETL nhẹ, nhưng than ôi ...
openwonk

3

Câu hỏi này đã cũ, nhưng tôi muốn thêm hai xu của mình. Tôi đọc câu hỏi là "Tôi muốn chạy một truy vấn đến cơ sở dữ liệu SQL [của tôi] và lưu trữ dữ liệu trả về dưới dạng cấu trúc dữ liệu Pandas [DataFrame]."

Từ mã có vẻ như bạn có nghĩa là cơ sở dữ liệu mysql và giả sử bạn có nghĩa là gấu trúc 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)

Ví dụ,

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

Thao tác này sẽ nhập tất cả các hàng của testTable vào DataFrame.


1

Đây là của tôi. Đề phòng nếu bạn đang sử dụng "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 đã KHÔNG ĐƯỢC SỬ DỤNG. https://pandas.pydata.org/pandas-docs/version/0.15.2/generated/pandas.io.sql.write_frame.html

Nên đổi sang dùng pandas.DataFrame.to_sql https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html

Có một giải pháp khác. PYODBC thành Pandas - DataFrame không hoạt động - Hình dạng của các giá trị được truyền là (x, y), các chỉ số ngụ ý (w, z)

Kể từ Pandas 0,12 (tôi tin rằng) bạn có thể làm:

import pandas
import pyodbc

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

data = pandas.read_sql(sql, cnn)

Trước 0.12, bạn có thể làm:

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

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

data = read_frame(sql, cnn)

Đây là cách dễ dàng nhất
Wilmer E. Henao

0

Còn lâu từ bài trước nhưng có lẽ nó giúp ích cho ai đó ...

Cách rút gọn hơn Paul H:

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

0

cách tốt nhất tôi làm điều này

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

0

Nếu loại kết quả là ResultSet , trước tiên bạn nên chuyển nó sang từ điển. Sau đó, các cột DataFrame sẽ được thu thập tự động.

Điều này hoạt động trên trường hợp của tôi:

df = pd.DataFrame([dict(r) for r in resoverall])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.