繁体   English   中英

如何使用 SQLAlchemy 定义没有主键的表?

[英]How to define a table without primary key with SQLAlchemy?

我有一张没有primary key 而且我真的不想将此约束应用于此表。

SQLAlchemy 中,我通过以下方式定义了表类:

class SomeTable(Base):
  __table__ = Table('SomeTable', meta, autoload=True, autoload_with=engine)

当我尝试查询此表时,我得到:

ArgumentError: Mapper Mapper|SomeTable|SomeTable could not assemble any primary key columns for mapped table 'SomeTable'.

如何失去每个表必须有一个主键的约束?

我知道只有一种方法可以绕过 SQL Alchemy 中的主键约束 - 将特定的一列或多列作为主键映射到您的表,即使它们本身不是主键。 http://docs.sqlalchemy.org/en/latest/faq/ormconfiguration.html#how-do-i-map-a-table-that-has-no-primary-key

对此没有适当的解决方案,但有解决方法:

解决方法 1

将参数 primary_key 添加到没有主键的现有列将起作用。

class SomeTable(Base):
    __table__ = 'some_table'
    some_other_already_existing_column = Column(..., primary_key=True) # just add primary key to it whether or not this column is having primary key or not

解决方法 2

只需在ORM 层上声明一个新的虚拟列,而不是在实际的 DB 中 只需在 SQLalchemy 模型中定义

class SomeTable(Base):
    __table__ = 'some_table'
    column_not_exist_in_db = Column(Integer, primary_key=True) # just add for sake of this error, dont add in db

免责声明:仅限 Oracle

Oracle 数据库秘密地存储称为rowid东西来唯一地定义表中的每条记录,即使该表没有主键。 我通过构建我的 ORM 对象解决了我缺少主键的问题(这不是我造成的!),例如:

class MyTable(Base)
    __tablename__ = 'stupid_poorly_designed_table'
    
    rowid = Column(String, primary_key=True)
    column_a = Column(String)
    column_b = Column(String)
    ...

您可以通过运行查看rowid实际外观(我相信这是一个十六进制值)

SELECT rowid FROM stupid_poorly_designed_table
GO

这是使用__mapper_args__合成 primary_key的示例。 因为表是面向时间序列的数据,所以不需要主键。 所有行都可以是具有(时间戳,对)元组的唯一地址。

class Candle(Base):

    __tablename__ = "ohlvc_candle"

    __table_args__ = (
        sa.UniqueConstraint('pair_id', 'timestamp'),
    )

    #: Start second of the candle
    timestamp = sa.Column(sa.TIMESTAMP(timezone=True), nullable=False)

    open = sa.Column(sa.Float, nullable=False)
    close = sa.Column(sa.Float, nullable=False)
    high = sa.Column(sa.Float, nullable=False)
    low = sa.Column(sa.Float, nullable=False)
    volume = sa.Column(sa.Float, nullable=False)

    pair_id = sa.Column(sa.ForeignKey("pair.id"), nullable=False)
    pair = orm.relationship(Pair,
                        backref=orm.backref("candles",
                                        lazy="dynamic",
                                        cascade="all, delete-orphan",
                                        single_parent=True, ), )

    __mapper_args__ = {
        "primary_key": [pair_id, timestamp]
    }

MSSQL 测试

我知道这个线程很古老,但我花了太长时间才让它工作而没有分享它:)

from sqlalchemy import Table, event
from sqlalchemy.ext.compiler import compiles
from sqlalchemy import Column
from sqlalchemy import Integer

class RowID(Column):
    pass


@compiles(RowID)
def compile_mycolumn(element, compiler, **kw):
    return "row_number() OVER (ORDER BY (SELECT NULL))"


@event.listens_for(Table, "after_parent_attach")
def after_parent_attach(target, parent):
    if not target.primary_key:
        # if no pkey create our own one based on returned rowid
        # this is untested for writing stuff - likely wont work
        logging.info("No pkey defined for table, using rownumber %s", target)
        target.append_column(RowID('row_id', Integer, primary_key=True))

https://docs-sqlalchemy-org.translate.goog/en/14/faq/ormconfiguration.html?_x_tr_sl=auto&_x_tr_tl=ru&_x_tr_hl=ru#how-do-i-map-a-table-that-has-no-首要的关键

一种方法:在 SQLAlchemy ORM 中,要映射到特定表,必须至少有一个列指定为主键列; 多列复合主键当然也是完全可能的。 这些列不需要被数据库知道为主键列。 列只需要像主键一样运行,例如行的不可为空的唯一标识符。

我的代码:

from ..meta import Base, Column, Integer, Date


class ActiveMinutesByDate(Base):
    __tablename__ = "user_computer_active_minutes_by_date"

    user_computer_id = Column(Integer(), nullable=False, primary_key=True)
    user_computer_date_check = Column(Date(), default=None,  primary_key=True)
    user_computer_active_minutes = Column(Integer(), nullable=True)

我找到的解决方案是向表中添加一个自动递增的主键列,然后将其用作主键。 数据库应该处理除此之外的所有其他事情。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM