从Pandas Dataframe 生成SQL语句

nue99wik  于 2023-03-11  发布在  其他
关注(0)|答案(9)|浏览(119)

我正在从各种来源(csv,xls,json等)加载数据到Pandas数据框,我想生成语句来创建和填充SQL数据库与此数据。有人知道一种方法来做到这一点吗?
我知道Pandas有一个to_sql函数,但那只适用于数据库连接,它不能生成字符串。

示例

我想要的是这样一个 Dataframe :

import pandas as pd
import numpy as np

dates = pd.date_range('20130101',periods=6)
df = pd.DataFrame(np.random.randn(6,4),index=dates,columns=list('ABCD'))

和一个函数,将产生这个(这个例子是PostgreSQL,但任何都可以):

CREATE TABLE data
(
  index timestamp with time zone,
  "A" double precision,
  "B" double precision,
  "C" double precision,
  "D" double precision
)
xqkwcwgp

xqkwcwgp1#

如果您只需要'CREATE TABLE' sql代码(而不需要插入数据),可以使用pandas.io.sql模块的get_schema函数:

In [10]: print pd.io.sql.get_schema(df.reset_index(), 'data')
CREATE TABLE "data" (
  "index" TIMESTAMP,
  "A" REAL,
  "B" REAL,
  "C" REAL,
  "D" REAL
)

一些注意事项:

  • 我不得不使用reset_index,因为它不包含索引
  • 如果你提供了一个特定数据库风格的sqlalchemy引擎,那么结果将被调整为该风格(例如数据类型名称)。
kcrjzv8t

kcrjzv8t2#

从 Dataframe 生成SQL创建语句

SOURCE = df
TARGET = data

从 Dataframe 生成SQL创建语句

def SQL_CREATE_STATEMENT_FROM_DATAFRAME(SOURCE, TARGET):

# SQL_CREATE_STATEMENT_FROM_DATAFRAME(SOURCE, TARGET)
# SOURCE: source dataframe
# TARGET: target table to be created in database

    import pandas as pd
    sql_text = pd.io.sql.get_schema(SOURCE.reset_index(), TARGET)   
    return sql_text

检查SQL CREATE TABLE语句字符串

print('\n\n'.join(sql_text))

从 Dataframe 生成SQL INSERT语句

def SQL_INSERT_STATEMENT_FROM_DATAFRAME(SOURCE, TARGET):
    sql_texts = []
    for index, row in SOURCE.iterrows():       
        sql_texts.append('INSERT INTO '+TARGET+' ('+ str(', '.join(SOURCE.columns))+ ') VALUES '+ str(tuple(row.values)))        
    return sql_texts

检查SQL INSERT INTO语句字符串

print('\n\n'.join(sql_texts))
yzckvree

yzckvree3#

插入语句解决方案

不确定这是否是最好的方法,但这比使用df.iterrows()更有效,因为df.iterrows()非常慢。而且,这在正则表达式的帮助下处理了nan值。

import re

def get_insert_query_from_df(df, dest_table):

    insert = """
    INSERT INTO `{dest_table}` (
        """.format(dest_table=dest_table)

    columns_string = str(list(df.columns))[1:-1]
    columns_string = re.sub(r' ', '\n        ', columns_string)
    columns_string = re.sub(r'\'', '', columns_string)

    values_string = ''

    for row in df.itertuples(index=False,name=None):
        values_string += re.sub(r'nan', 'null', str(row))
        values_string += ',\n'

    return insert + columns_string + ')\n     VALUES\n' + values_string[:-2] + ';'
q3qa4bjr

q3qa4bjr4#

如果你想自己写这个文件,你也可以检索列名和数据类型,并建立一个字典来把panda数据类型转换成sql数据类型。
例如:

import pandas as pd
import numpy as np

dates = pd.date_range('20130101',periods=6)
df = pd.DataFrame(np.random.randn(6,4),index=dates,columns=list('ABCD'))

tableName = 'table'
columnNames = df.columns.values.tolist()
columnTypes =  map(lambda x: x.name, df.dtypes.values)

# Storing column names and dtypes in a dataframe

tableDef = pd.DataFrame(index = range(len(df.columns) + 1), columns=['cols', 'dtypes'])

tableDef.iloc[0]           = ['index', df.index.dtype.name]
tableDef.loc[1:, 'cols']   = columnNames
tableDef.loc[1:, 'dtypes'] = columnTypes

# Defining a dictionnary to convert dtypes

conversion = {'datetime64[ns]':'timestamp with time zone', 'float64':'double precision'}

# Writing sql in a file

f = open('yourdir\%s.sql' % tableName, 'w')

f.write('CREATE TABLE %s\n' % tableName)
f.write('(\n')

for i, row in tableDef.iterrows():
    sep = ",\n" if i < tableDef.index[-1] else "\n"
    f.write('\t\"%s\" %s%s' % (row['cols'], conversion[row['dtypes']], sep))

f.write(')')

f.close()

您可以使用INSERT INTO以相同的方式填充表。

gtlvzcf8

gtlvzcf85#

单次插入查询解决方案

我没有找到适合我需要的以上答案。我想为一个 Dataframe 创建一个单插入语句,每一行作为值。这可以通过以下方式实现:

import re 
import pandas as pd 

table = 'your_table_name_here'

# You can read from CSV file here... just using read_sql_query as an example

df = pd.read_sql_query(f'select * from {table}', con=db_connection)

cols = ', '.join(df.columns.to_list()) 
vals = []

for index, r in df.iterrows():
    row = []
    for x in r:
        row.append(f"'{str(x)}'")

    row_str = ', '.join(row)
    vals.append(row_str)

f_values = [] 
for v in vals:
    f_values.append(f'({v})')

# Handle inputting NULL values
f_values = ', '.join(f_values) 
f_values = re.sub(r"('None')", "NULL", f_values)

sql = f"insert into {table} ({cols}) values {f_values};" 

print(sql)

db.dispose()
r6l8ljro

r6l8ljro6#

如果你只是想生成一个基于pandas.DataFrame的插入字符串,我建议使用@rup建议的批量sql插入语法。
下面是我为此编写的function示例:

import pandas as pd
import re

def df_to_sql_bulk_insert(df: pd.DataFrame, table: str, **kwargs) -> str:
    """Converts DataFrame to bulk INSERT sql query
    >>> data = [(1, "_suffixnan", 1), (2, "Noneprefix", 0), (3, "fooNULLbar", 1, 2.34)]
    >>> df = pd.DataFrame(data, columns=["id", "name", "is_deleted", "balance"])
    >>> df
       id        name  is_deleted  balance
    0   1  _suffixnan           1      NaN
    1   2  Noneprefix           0      NaN
    2   3  fooNULLbar           1     2.34
    >>> query = df_to_sql_bulk_insert(df, "users", status="APPROVED", address=None)
    >>> print(query)
    INSERT INTO users (id, name, is_deleted, balance, status, address)
    VALUES (1, '_suffixnan', 1, NULL, 'APPROVED', NULL),
           (2, 'Noneprefix', 0, NULL, 'APPROVED', NULL),
           (3, 'fooNULLbar', 1, 2.34, 'APPROVED', NULL);
    """
    df = df.copy().assign(**kwargs)
    columns = ", ".join(df.columns)
    tuples = map(str, df.itertuples(index=False, name=None))
    values = re.sub(r"(?<=\W)(nan|None)(?=\W)", "NULL", (",\n" + " " * 7).join(tuples))
    return f"INSERT INTO {table} ({columns})\nVALUES {values};"

顺便说一下,它将nan/None条目转换为NULL,并且可以将常量column=value对作为关键字参数传递(请参见docstring示例中的status="APPROVED"address=None参数)。
通常,它的工作速度更快,因为任何数据库都要为单个插入做大量工作:检查约束、建立索引、刷新、写入日志等。这种复杂的操作可以由数据库在进行多合一操作时进行优化,而不是逐个调用引擎。

wpx232ag

wpx232ag7#

我以用户@Jaris的帖子为例,进一步扩展了CREATE,使其适用于任何CSV

import sqlite3
import pandas as pd

db = './database.db'
csv = './data.csv'
table_name = 'data'

# create db and setup schema
df = pd.read_csv(csv)
create_table_sql = pd.io.sql.get_schema(df.reset_index(), table_name)
conn = sqlite3.connect(db)
c = conn.cursor()
c.execute(create_table_sql)
conn.commit()

# now we can insert data
def insert_data(row, c):
    values = str(row.name)+','+','.join([str('"'+str(v)+'"') for v in row])
    sql_insert=f"INSERT INTO {table_name} VALUES ({values})"

    try:
        c.execute(sql_insert)
    except Exception as e:
        print(f"SQL:{sql_insert} \n failed with Error:{e}")


# use apply to loop over dataframe and call insert_data on each row
df.apply(lambda row: insert_data(row, c), axis=1)

# finally commit all those inserts into the database
conn.commit()

希望这是更简单的比替代答案和更多的Python!

cl25kdpy

cl25kdpy8#

这取决于您是否可以放弃生成SQL语句的中间表示形式;您也可以直接执行insert语句。

con.executemany("INSERT OR REPLACE INTO data (A, B, C, D) VALUES (?, ?, ?, ?, ?)", list(df_.values))

这工作得稍微好一点,因为有更少的混乱与字符串生成。

piwo6bdm

piwo6bdm9#

我使用的解决方案是使用SQLite3将 * Dataframe * 发送到 * 内存 * 中的DB。
然后,我转储DB,将语句写入 .sql 文件。
...只是为了演示,我创建了一个示例文件:

from datetime import datetime

import pandas as pd
import seaborn as sns
from sqlalchemy import create_engine

# Load Dataset
dataset_name = 'iris'
df = sns.load_dataset(dataset_name)

# Add Name to Index
df.index.name = 'Id'

# Results
df.head()

我们使用SQL Alchemy创建了一个 engine,这个连接将被 * panda * 用来把数据发送到临时内存,也被***SQLite3用来 * 转储database 的内容。

# Create Engine with SQL Alchemy (used by pandas)
engine = create_engine(f'sqlite://', echo=False)

# Send data to temporary SQLite3
df.to_sql(name=dataset_name, index=True, con=engine, if_exists='replace')

最后,我们指出输出文件的路径并执行 iterdump

# Output file
output_file = f'sql - {dataset_name}.sql'

# Para cada
with open(output_file, 'w') as f:
    # Date
    data_agora = datetime.today().strftime('%Y.%m.%d %H:%M:%S')
    
    f.write(
        '/****** Query para criação e inserção de registros no DB ******/\n'
    )
    f.write('/*\n')
    f.write(f'São {len(df)} registros\n')
    f.write(f'Obtidos na tabela "{dataset_name}"\n')
    f.write('\n')
    f.write(f'Query feita por Michel Metran em {(data_agora)},\n')
    f.write('*/\n')
    f.write('\r\n')    
    
    with engine.connect() as conn:
        for line in conn.connection.iterdump():            
            f.write(f'{line}\n')
            print(line)
    
    # Close Connection
    conn.close()

为了让生活更轻松,我在我维护的包中创建了一个函数,称为“traquitanas”,函数是安装包和使用函数所必需的:

#!pip3 install traquitanas --upgrade
from traquitanas.data import convert_to_sql

convert_to_sql.convert_dataframe_to_sql(df, output_file, dataset_name)

相关问题