SQL Sorgusu sonucunu PANDAS Veri Yapısına nasıl dönüştürebilirim?


117

Bu sorunla ilgili herhangi bir yardım çok takdir edilecektir.

Bu yüzden temelde SQL veritabanımda bir sorgu çalıştırmak ve döndürülen verileri Pandas veri yapısı olarak depolamak istiyorum.

Sorgu için kod ekledim.

Pandalar hakkındaki belgeleri okuyorum, ancak sorgumun dönüş türünü belirlemekte sorun yaşıyorum.

Sorgu sonucunu yazdırmaya çalıştım, ancak herhangi bir yararlı bilgi vermedi.

Teşekkürler!!!!

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)

Bu yüzden "resoverall" değişkenimin formatının / veri türünün ne olduğunu ve bunu PANDAS veri yapısına nasıl koyacağımı anlamak istiyorum.


Temel olarak, "resoverall" değişkeninin yapısı / türü nedir ve bunu Pandas veri yapısına nasıl dönüştürülür.
user1613017

Pandalar kulağa oldukça ilginç geliyor, daha önce duymamıştım ama bu soru çok az mantıklı. "Hiçbir yararlı bilgi vermez" derken neyi kastettiğinizi netleştirebilir misiniz?
tadman

1
Yürüttüğüm sorgu bir dönüş verdiğinden, bu dönüşü nasıl değiştirip pandalar veri yapısına dönüştürmeliyim diye merak ediyorum. Python'da çok yeniyim ve bu nedenle PHP'de yaptığımız şey sadece bir sql_fetch_array yapmak ve "kullanılabilir" veriye sahip olmak gibi çok fazla bilgiye sahip değilim. =)
user1613017

Yanıtlar:


120

İşte işi yapacak en kısa kod:

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

Daha meraklı gidebilir ve türleri Paul'ün cevabında olduğu gibi ayrıştırabilirsiniz.


1
Bu benim için bir Oracle veritabanından alınan 1.000.000 kayıt için çalıştı.
Erdem KAYA

8
df = DataFrame(cursor.fetchall())döndürürse ValueError: DataFrame constructor not properly called!, tuple demetinin DataFrame yapıcısı için kabul edilebilir olmadığı anlaşılır. .keys()Sözlük veya tuple modunda imleç üzerinde de yoktur .
Mobigital

3
Anahtarlar yönteminin yalnızca sqlalchemy kullanılarak elde edilen sonuçlarla çalışacağını unutmayın. Pyodbc, sütunlar için açıklama özelliğini kullanır.
Filip

Bu Postgres veritabanları için çalışabilir mi? İşlev ile sonuç veri çerçevesi için sütun adlarını almaya çalışıyorum keys()ancak çalışmasını sağlayamıyorum.
Bowen Liu

1
@BowenLiu Evet, psycopg2 ile kullanabilirsinizdf.columns=[ x.name for x in recoverall.description ]
Gnudiff

138

Düzenleme: Mart 2015

Aşağıda belirtildiği gibi, pandalar artık SQLAlchemy'yi hem okumak ( read_sql ) hem de eklemek için ( bir veritabanından bir veritabanına to_sql ) . Aşağıdakiler çalışmalı

import pandas as pd

df = pd.read_sql(sql, cnxn)

Önceki cevap: Benzer bir sorudan mikebmassey ile

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

Sütun dizinini almak için .keys () 'i manuel olarak kullanmanız gerekmediğinden, bunu yapmanın en iyi yolu bu gibi görünüyor. Muhtemelen Daniel'ın cevabı bu yöntem var olmadan önce yazılmıştır. Ayrıca pandas.io.sql.read_frame ()
RobinL

1
@openwonk pd.read_sql()yukarıdaki kod parçacığını nereye uygular ?
3kstc

Aslında benim son yanıt yana, ben kullandım pyodbcve pandasbiraz birlikte. Örnekle yeni cevap ekleniyor, FYI.
openwonk

33

İfade dili yerine SQLAlchemy'nin ORM'sini kullanıyorsanız, kendinizi bir nesneyi dönüştürmek isteyebilirsiniz. sqlalchemy.orm.query.Query Pandas veri çerçevesine .

En temiz yaklaşım, üretilen SQL'i sorgunun deyim özniteliğinden almak ve ardından bunu pandas'ın read_sql()yöntemi ile yürütmektir . Örneğin, bir Sorgu nesnesiyle başlayarak query:

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

5
Daha verimli bir yaklaşım sqlalchemy gelen deyimi almak ve pandalar ile sorgu kendisi yapalım etmektir pandas.read_sql_querygeçen query.statementona. Bu yanıtı görün: stackoverflow.com/a/29528804/1273938
LeoRochael

Teşekkürler @LeoRochael! Cevabımı düzenledim. Kesinlikle daha temiz!
Nathan Gould

23

2014-09-30'u düzenleyin:

Pandaların artık bir read_sql işlevi var. Kesinlikle onu kullanmak istiyorsun.

Orijinal cevap:

SQLAlchemy konusunda size yardımcı olamam - Gerektiğinde her zaman pyodbc, MySQLdb veya psychopg2 kullanırım. Ancak bunu yaparken, aşağıdaki kadar basit bir işlev ihtiyaçlarımı karşılama eğilimindedir:

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

Sanırım ondalık sayıları üstte bir yere aktarmanız gerekiyor?
joefromct

@joefromct Belki, ama bu cevap o kadar eski ki, gerçekten her şeye değinmeli ve pandaların yöntemlerini göstermeliyim.
Paul H

Bazıları için alakalı olabilir ... bunu çalışmamın nedeni diğer sorunumdu, read_sql () burada stackoverflow.com/questions/32847246/…
joefromct

Tüm veritabanlarını desteklemeyen SQLAlchemy kullanamayanlar için geçerlidir.
lamecicle

@lamecicle biraz katılmıyorum. IIRC, read_sqlörneğin pyodbc, psychopg2, vb. Yoluyla SQLAlchemy dışı bağlantıları kabul edebilir
Paul H

16

MySQL Bağlayıcısı

Mysql konektörü ile çalışanlar için bu kodu başlangıç ​​olarak kullanabilirsiniz. (@Daniel Velkov'a teşekkürler)

Kullanılan referanslar:


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

İşte kullandığım kod. Bu yardımcı olur umarım.

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

Bu, sorununuz için kısa ve net bir cevaptır:

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)

9

1. MySQL-connector-python kullanma

# 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'yi Kullanma

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

basit ve harika bir cevap!
Lucas Aimaretto

5

Nathan gibi ben de sık sık bir sqlalchemy veya sqlsoup Query'nin sonuçlarını Pandas veri çerçevesine aktarmak istiyorum. Bunun için kendi çözümüm:

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

1
Bir sorgu nesneniz varsa. Bu sqlalchemy gelen deyimi almak ve pandalar ile sorgu kendisi yapalım daha etkin olur pandas.read_sql_querygeçerek query.statementkendisine. Bu yanıtı görün: stackoverflow.com/a/29528804/1273938
LeoRochael

4

resoverallbir sqlalchemy ResultProxy nesnesidir. Bu konuda daha fazla bilgiyi sqlalchemy belgelerinde okuyabilirsiniz , ikincisi Motorlar ve Bağlantılar ile çalışmanın temel kullanımını açıklar. Burada önemli olan şuresoverall , böyle dikte olmasıdır.

Pandalar, veri yapılarını oluşturmak için nesneler gibi dikte etmeyi severler. çevrimiçi belgelere bakın

Sqlalchemy ve pandalarda iyi şanslar.


4

Basitçe pandasve pyodbcbirlikte kullanın . connstrVeritabanınızın özelliklerine göre bağlantı dizenizi ( ) değiştirmeniz gerekecektir .

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Çeşitli kurumsal veritabanları ile kullandım (örn. SQL Server, MySQL, MariaDB, IBM).


Pyodbc kullanarak bu veri çerçevesini tekrar MSSQL'e nasıl yazabilirim? Otherthan sqlalchemy kullanmaktan
Ramsey

Nesne to_sqlüzerinde yöntemi kullanın DataFrame. Bu yöntem varsayılan olarak SQLite'dir, bu nedenle ona MSSQL veritabanına işaret eden bir nesneyi açıkça iletmeniz gerekir. Belgelere bakın .
openwonk

Aşağıdakini denedim ve 13 sütunlu yaklaşık 200 bin satırım var. 15 dakika sonra da tamamlanmaz. Herhangi bir fikir? df.to_sql ('tablename', engine, schema = 'schemaname', if_exists = 'append', index = False)
Ramsey

Bu yavaş görünüyor ... Muhtemelen kodun tamamını çalışırken görmem gerekir, üzgünüm. Keşke pandashafif ETL çalışması için daha optimize edilmiş olsaydı , ama ne yazık ki ...
openwonk

3

Bu soru eski ama iki sentimi de eklemek istedim. Soruyu "SQL veritabanımda bir sorgu çalıştırmak ve döndürülen verileri Pandas veri yapısı [DataFrame] olarak saklamak istiyorum." Şeklinde okudum.

Koddan mysql veritabanını kastediyorsunuz ve pandalar DataFrame'i kastettiğinizi varsayıyorsunuz.

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)

Örneğin,

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

Bu, tüm testTable satırlarını bir DataFrame'e aktaracaktır.


1

İşte benim. Her ihtimale karşı "pymysql" kullanıyorsanız:

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 KULLANIMDAN KALDIRILDI. https://pandas.pydata.org/pandas-docs/version/0.15.2/generated/pandas.io.sql.write_frame.html

Pandas.DataFrame.to_sql kullanmak için değiştirilmelidir https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html

Başka bir çözüm var. PYODBC'den Pandalara - DataFrame çalışmıyor - Aktarılan değerlerin şekli (x, y), endeksler (w, z) anlamına geliyor

Pandalar 0.12'den itibaren (inanıyorum) şunları yapabilirsiniz:

import pandas
import pyodbc

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

data = pandas.read_sql(sql, cnn)

0.12'den önce şunları yapabilirdiniz:

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

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

data = read_frame(sql, cnn)

Bu açık arayla en kolay yol
Wilmer E. Henao

0

Son gönderiden uzun zaman geçti ama belki birine yardımcı olur ...

Paul H'den daha kısa yol:

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

0

bunu yapmanın en iyi yolu

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

0

Sonuç türü ResultSet ise , önce onu sözlüğe dönüştürmelisiniz. Ardından DataFrame sütunları otomatik olarak toplanacaktır.

Bu benim durumumda çalışıyor:

df = pd.DataFrame([dict(r) for r in resoverall])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.