【问题标题】:SQLAlchemy bulk insert with missing values using default valuesSQLAlchemy 使用默认值批量插入缺失值
【发布时间】:2017-07-17 05:18:55
【问题描述】:

问题陈述 -

我想使用 SQLAlchemy 批量插入几百行。架构如下所示

all_scrips_tbl = Table('all_scrips_info', _METADATA, Column('security_isin', String(16), primary_key=True), Column('company_name', String(80)), Column('nse_traded', Boolean, default=False), Column('nse_start_date', Date, default=datetime.date(year=2001, day=1, month=1)), Column('bse_traded', Boolean, default=False), Column('bse_start_date', Date, default=datetime.date(year=2001, day=1, month=1)), ) 现在每个脚本可以是 - nse_traded=Truebse_traded=True 或两者兼有 nse_traded=True and bse_traded=True

所以我有插入语句,例如 -

对于只有nse_traded=True 的证券 ins = t.insert().values(security_isin=nstock.isin, company_name=nstock.name, nse_traded=True, nse_start_date=nstart_date, )

对于只有bse_traded=True 的证券 -

ins = t.insert().values(security_isin=bstock.isin, company_name=bstock.name, bse_traded=True, bse_start_date=bstart_date)

对应nse_traded=Truebse_traded=True

我想批量插入这些语句。因此,像 values().compile 这样的带有来自 create 语句的默认值的东西会非常有用,这样我就可以使用以下内容 -

conn.execute(all_scrips_info.insert() , [ {}, {} ] ) dicts 在哪里填充了适当的默认值?

我还查看了this 问题,但这与我的要求略有不同。有一个old question on google groups 与我的要求相似。但是那里的sqlalchemy版本比较老,而且答案不是很容易理解。

我是否遗漏了一些非常明显的东西?

【问题讨论】:

  • 我是否正确理解您有一个数据集,其中包含三个组的记录:(1) nse_traded、(2) bse_traded 和 (3) nse_traded 和 bse_traded,并且您想批量插入这些记录?
  • 是的,没错——我还在适用的地方定义了默认值。我现在正在做的是使用values 生成insert 语句并在像execute(insert) 这样的循环中运行它们。我想使用execute(insert, [{}, {}]),当我没有在insert.values 中明确使用它们时,使用默认值。

标签: python sqlalchemy sql-insert


【解决方案1】:

下面我提供了一个简单的示例,说明如何使用 SQLAlchemy 更轻松地将 CSV 文件中的数据插入到数据库中。这里的默认值是创建日期。在 init 函数中你可以添加更多逻辑...这个逻辑在创建对象时应用。

我想指出其他方法是可用的。例如参见 SQLAlchemy 文档:http://docs.sqlalchemy.org/en/latest/orm/persistence_techniques.html#bulk-operations

例子:

import csv
from io import StringIO
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from datetime import datetime

# Setting up model

Base = declarative_base()


class Car(Base):
    __tablename__ = 'car'

    id = Column('id', Integer, primary_key=True)
    created = Column('created', DateTime, default=datetime.now())
    brand = Column(String(250))
    nr_gears = Column('nr_gears', Integer)

    def __init__(self, brand, nr_gears):
        self.brand = brand
        self.nr_gears = nr_gears

        # You can place logic,conditions here when creating the objects. Now only use of default date - creation

    def __repr__(self):
        return '{created}\t{brand} (nr of gears: {nr_gears})'.format(
            created=datetime.strftime(self.created, '%d/%m/%Y'), brand=self.brand, nr_gears=self.nr_gears)


engine = create_engine('sqlite:///')
session = sessionmaker()
session.configure(bind=engine)
ex_ses = session()
Base.metadata.create_all(engine)

# Reading in some dummy data

csv_data = \
    '''Audi,5
    BMW,5
    Mercedes-Benz,5
    Opel,5
    Porsche,6
    Volkswagen,5
    Acura,5
    Datsun,6
    Honda,6
    Infiniti,5
    Isuzu,6
    Lexus,5
    Mazda,5
    Mitsubishi,5
    Nissan,5
    Suzuki,6
    Toyota,6
    Subaru,6'''

with StringIO(csv_data) as car_csv:
    cars_data = []
    readCSV = csv.reader(car_csv, delimiter=',')
    for row in readCSV:
        # Add data to the session.
        ex_ses.add(Car(brand=row[0], nr_gears=row[1]))

ex_ses.commit()

# Query
cars = (ex_ses.query(Car).all())
print('Created\t\tBrand (nr of gears)')
print('-' * 45)
for car in cars:
    print(car)

# output:
'''
Created     Brand (nr of gears)
---------------------------------------------
18/07/2017  Audi (nr of gears: 5)
18/07/2017  BMW (nr of gears: 5)
18/07/2017  Mercedes-Benz (nr of gears: 5)
18/07/2017  Opel (nr of gears: 5)
18/07/2017  Porsche (nr of gears: 6)
18/07/2017  Volkswagen (nr of gears: 5)
18/07/2017  Acura (nr of gears: 5)
18/07/2017  Datsun (nr of gears: 6)
18/07/2017  Honda (nr of gears: 6)
18/07/2017  Infiniti (nr of gears: 5)
18/07/2017  Isuzu (nr of gears: 6)
18/07/2017  Lexus (nr of gears: 5)
18/07/2017  Mazda (nr of gears: 5)
18/07/2017  Mitsubishi (nr of gears: 5)
18/07/2017  Nissan (nr of gears: 5)
18/07/2017  Suzuki (nr of gears: 6)
18/07/2017  Toyota (nr of gears: 6)
18/07/2017  Subaru (nr of gears: 6)
'''

希望这会有所帮助。

编辑: 基于 cmets,我在下面扩展了 Car 类。如果缺少齿轮数...使用默认值九。这当然是一个有限的例子,但(我希望)展示了使用默认值的可能性......

class Car(Base):
    __tablename__ = 'car'

    id = Column('id', Integer, primary_key=True)
    created = Column('created', DateTime, default=datetime.now())
    brand = Column(String(250))
    nr_gears = Column('nr_gears', Integer,default=None)

    def __init__(self, brand, nr_gears):
        self.brand = brand

        if nr_gears is None or nr_gears == '':
            nr_gears = 9

        self.nr_gears = nr_gears

        # You can place logic,conditions here when creating the objects. Now only use of default date - creation

    def __repr__(self):
        return '{created}\t{brand} (nr of gears: {nr_gears})'.format(
            created=datetime.strftime(self.created, '%d/%m/%Y'), brand=self.brand, nr_gears=self.nr_gears)

【讨论】:

  • 您的解决方案存在一些问题,因此无法接受。 1.想象一下,如果您的 CSV 文件对于某些模型根本没有“gears”条目,并且在您的 DDL 中您提到它为 5。所以每当我不指定它时,请使用 5(“默认”属性的真正目的)。 SA 批量插入的问题是 - 语法 execte(table.insert, [{dict of values}]) 要求大小“对所有字典都相同”。如果我的数据确实来自一个 CSV 文件,我也许可以这样写——它来自两组(从不同的地方填充)。
  • 忽略 SA 批量插入的问题。关于如何定义和插入缺失值的默认值的进一步问题(如果值完全从 CSV...0 中丢失?这可以在 init 中实现。如果这(我对问题的解释)是正确的我将更新示例。
  • 是的 - 但我不想在 SA 之外进行繁重的工作 - 我只是在想是否有一种更简单的方法我错过了,而 SA 已经提供了。
猜你喜欢
  • 1970-01-01
  • 2011-04-09
  • 1970-01-01
  • 2021-11-20
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
  • 2018-09-14
  • 2011-08-05
相关资源
最近更新 更多