SQLAlchemy表达式语言 - 使用文字值INSERT SELECT

时间:2018-01-23 23:25:16

标签: python sqlalchemy

我刚刚开始使用SQLAlchemy SQL表达式语言,并且我试图从现有表和文字值插入表值。我试图用SQL表达式语言模拟这个SQL语句:

INSERT INTO b_Customers 
(CustomerID, 
CustomerName, 
CustomerType,
IsCurrent,
FirstObserved,
LastObserved)

SELECT CustomerID, CustomerName, CustomerType, 1, '2018-01-23', '2018-01-23'
FROM s_Customers

这是我正在运行的一些设置Python代码:

from datetime import datetime
from io import StringIO
import csv

from sqlalchemy import create_engine, Table, Column, Integer, Date, String, MetaData, ForeignKey, bindparam, text
from sqlalchemy.sql import select
from sqlalchemy.sql.expression import literal_column, literal

engine = create_engine('sqlite:///:memory:')

metadata = MetaData()
stage = Table('s_Customers', metadata,
    Column('CustomerID', Integer, primary_key=True),
    Column('CustomerName', String),
    Column('CustomerType', String),
)

base = Table('b_Customers', metadata,
    Column('CustomerID', Integer, primary_key=True),
    Column('CustomerName', String),
    Column('CustomerType', String),
    Column('IsCurrent', Integer),
    Column('FirstObserved', Date),
    Column('LastObserved', Date),
)

metadata.create_all(engine)

insert_data = u'''CustomerID,CustomerName,CustomerType
1,Jannet,Preferred
2,Daniel,Regular
3,Casper,Regular'''

table_to_insert = StringIO(insert_data)
table_values = list(csv.DictReader(table_to_insert))

conn = engine.connect()
stmt = stage.insert().values(table_values)
conn.execute(stmt)

这就是我被困的地方:

stmt = base.insert().from_select(list(stage.columns) + [bindparam(1, 'IsCurrent'), 
                                                        bindparam(datetime(2018, 1, 23), 'FirstObserved'), 
                                                        bindparam(datetime(2018, 1, 23), 'LastObserved')],
                                stage)
conn.execute(stmt)

这是运行上述代码的堆栈跟踪:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-35-a3d52b22c83e> in <module>()
      3                                                         bindparam(datetime(2018, 1, 23), 'LastObserved')],
      4                                 stage)
----> 5 conn.execute(stmt)

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\engine\base.pyc in execute(self, object, *multiparams, **params)
    946             raise exc.ObjectNotExecutableError(object)
    947         else:
--> 948             return meth(self, multiparams, params)
    949 
    950     def _execute_function(self, func, multiparams, params):

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\elements.pyc in _execute_on_connection(self, connection, multiparams, params)
    267     def _execute_on_connection(self, connection, multiparams, params):
    268         if self.supports_execution:
--> 269             return connection._execute_clauseelement(self, multiparams, params)
    270         else:
    271             raise exc.ObjectNotExecutableError(self)

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\engine\base.pyc in _execute_clauseelement(self, elem, multiparams, params)
   1051                 inline=len(distilled_params) > 1,
   1052                 schema_translate_map=self.schema_for_object
-> 1053                 if not self.schema_for_object.is_default else None)
   1054 
   1055         ret = self._execute_context(

<string> in <lambda>(self, bind, dialect, **kw)

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\elements.pyc in compile(self, default, bind, dialect, **kw)
    440             else:
    441                 dialect = default.StrCompileDialect()
--> 442         return self._compiler(dialect, bind=bind, **kw)
    443 
    444     def _compiler(self, dialect, **kw):

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\elements.pyc in _compiler(self, dialect, **kw)
    446         Dialect."""
    447 
--> 448         return dialect.statement_compiler(dialect, self, **kw)
    449 
    450     def __str__(self):

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\compiler.pyc in __init__(self, dialect, statement, column_keys, inline, **kwargs)
    451         # dialect.label_length or dialect.max_identifier_length
    452         self.truncated_names = {}
--> 453         Compiled.__init__(self, dialect, statement, **kwargs)
    454 
    455         if (

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\compiler.pyc in __init__(self, dialect, statement, bind, schema_translate_map, compile_kwargs)
    217             if self.can_execute:
    218                 self.execution_options = statement._execution_options
--> 219             self.string = self.process(self.statement, **compile_kwargs)
    220 
    221     @util.deprecated("0.7", ":class:`.Compiled` objects now compile "

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\compiler.pyc in process(self, obj, **kwargs)
    243 
    244     def process(self, obj, **kwargs):
--> 245         return obj._compiler_dispatch(self, **kwargs)
    246 
    247     def __str__(self):

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\visitors.pyc in _compiler_dispatch(self, visitor, **kw)
     79                     raise exc.UnsupportedCompilationError(visitor, cls)
     80                 else:
---> 81                     return meth(self, **kw)
     82         else:
     83             # The optimization opportunity is lost for this case because the

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\compiler.pyc in visit_insert(self, insert_stmt, asfrom, **kw)
   2032 
   2033         crud_params = crud._setup_crud_params(
-> 2034             self, insert_stmt, crud.ISINSERT, **kw)
   2035 
   2036         if not crud_params and \

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\crud.pyc in _setup_crud_params(compiler, stmt, local_stmt_type, **kw)
     55     try:
     56         if local_stmt_type in (ISINSERT, ISUPDATE):
---> 57             return _get_crud_params(compiler, stmt, **kw)
     58     finally:
     59         if should_restore:

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\crud.pyc in _get_crud_params(compiler, stmt, **kw)
    130             compiler, stmt, parameters,
    131             _getattr_col_key, _column_as_key,
--> 132             _col_bind_name, check_columns, values, kw)
    133     else:
    134         _scan_cols(

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\sql\crud.pyc in _scan_insert_from_select_cols(compiler, stmt, parameters, _getattr_col_key, _column_as_key, _col_bind_name, check_columns, values, kw)
    211 
    212     cols = [stmt.table.c[_column_as_key(name)]
--> 213             for name in stmt.select_names]
    214 
    215     compiler._insert_from_select = stmt.select

C:\Users\rdelgado\AppData\Local\Continuum\Anaconda2\Lib\site-packages\sqlalchemy\util\_collections.pyc in __getitem__(self, key)
    192 
    193     def __getitem__(self, key):
--> 194         return self._data[key]
    195 
    196     def __delitem__(self, key):

KeyError: 1

我也尝试过使用literal()和literal_column(),这些都没有成功。

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

我知道了。我必须创建另一个可选择的文本列,然后从中选择:

stage_w_columns = select(list(stage.columns) + [literal(1).label('IsCurrent'),
                                           literal(datetime(2018, 1, 23)).label('FirstObserved'),
                                           literal(datetime(2018, 1, 23)).label('LastObserved')])
stmt = base.insert().from_select(stage_w_columns.columns, stage_w_columns)
conn.execute(stmt)

感谢路易斯指出我正确的方向!