从Pandas Dataframe生成SQL语句

Jor*_*zen 13 python sql pandas

我正在从各种来源(csv,xls,json等...)加载数据到Pandas数据帧,我想生成语句来创建和填充这个数据的SQL数据库.有谁知道这样做的方法?

我知道pandas有一个to_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'))
Run Code Online (Sandbox Code Playgroud)

并且会生成一个函数(这个例子是PostgreSQL,但任何都可以):

CREATE TABLE data
(
  index timestamp with time zone,
  "A" double precision,
  "B" double precision,
  "C" double precision,
  "D" double precision
)
Run Code Online (Sandbox Code Playgroud)

jor*_*ris 20

如果您只想要'CREATE TABLE'的sql代码(而不是数据的插入),则可以使用get_schemapandas.io.sql模块的功能:

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
)
Run Code Online (Sandbox Code Playgroud)

一些说明:

  • 我不得不使用,reset_index因为它不包括索引
  • 如果您提供某种数据库风格的sqlalchemy引擎,则结果将调整为该风格(例如数据类型名称).

  • 是否可以获取插入数据,以便进行更新/插入? (3认同)
  • @joris如何指定sqlalchemy引擎? (3认同)
  • 我看到 RustyShackleford 已经找到了它,但指定引擎的方式如下:/sf/answers/3590626931/ (2认同)

Jan*_*ang 20

从 DATAFRAME 生成 SQL 创建语句

SOURCE = df
TARGET = data
Run Code Online (Sandbox Code Playgroud)

从 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
Run Code Online (Sandbox Code Playgroud)

检查 SQLCREATE TABLE语句字符串

print('\n\n'.join(sql_text))
Run Code Online (Sandbox Code Playgroud)

从 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
Run Code Online (Sandbox Code Playgroud)

检查 SQLINSERT INTO语句字符串

print('\n\n'.join(sql_texts))
Run Code Online (Sandbox Code Playgroud)

  • 我尝试了这个插入语句,但它似乎不处理 Nulls 。生成的 Insert 语句对于 NULL 值有 nan,我的查询尝试在这些字段中插入 nan。 (5认同)

小智 10

插入语句解决方案

不确定这是否是绝对最好的方法,但这比使用更有效,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] + ';'
Run Code Online (Sandbox Code Playgroud)


abs*_*oup 6

如果您只是想生成一个带有基于插入的字符串pandas.DataFrame- 我建议使用 @rup 建议的批量 sql 插入语法。

这是我为此目的编写的函数的示例:

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};"
Run Code Online (Sandbox Code Playgroud)

顺便说一句,它将nan/None条目转换为NULL并且可以将常量 column=value 对作为关键字参数传递(请参阅文档字符串示例中的status="APPROVED"address=None参数)。

一般来说,它的工作速度更快,因为任何数据库都会为单个插入做很多工作:检查约束、构建索引、刷新、写入日志等。在执行多合一操作时,数据库可以优化这种复杂的操作,而不是一一调用引擎。