How to define a table without primary key with SQLAlchemy?

Question:

I have a table that does not have a primary key. And I really do not want to apply this constraint to this table.

In SQLAlchemy, I defined the table class by:

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

When I try to query this table, I got:

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

How to loss the constraint that every table must have a primary key?

Asked By: David S.

||

Answers:

There is only one way that I know of to circumvent the primary key constraint in SQL Alchemy – it’s to map specific column or columns to your table as a primary keys, even if they aren’t primary key themselves.
http://docs.sqlalchemy.org/en/latest/faq/ormconfiguration.html#how-do-i-map-a-table-that-has-no-primary-key.

Answered By: mta194

There is no proper solution for this but there are workarounds for it:

Workaround 1

Adding parameter primary_key to the existing column that is not having a primary key will work.

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

Workaround 2

Just declare a new dummy column on the ORM layer, not in actual DB. Just define in SQLalchemy model

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
Answered By: Anand Tripathi

Disclaimer: Oracle only

Oracle databases secretly store something called rowid to uniquely define each record in a table, even if the table doesn’t have a primary key. I solved my lack of primary key problem (which I did not cause!) by constructing my ORM object like:

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

You can see what rowid actually looks like (it’s a hex value I believe) by running

SELECT rowid FROM stupid_poorly_designed_table
GO
Answered By: medley56

The solution I found is to add an auto-incrementing primary key column to the table, then use that as your primary key. The database should deal with everything else beyond that.

Answered By: pyro hedgehog

Here is an example using __mapper_args__ and a synthetic primary_key. Because the table is time-series oriented data, there is no need for a primary key. All rows can be unique addresses with a (timestamp, pair) tuple.

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]
    }
Answered By: Mikko Ohtamaa

MSSQL Tested

I know this thread is ancient but I spent way too long getting this to work to not share it 🙂

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))
Answered By: Nick Holden

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-primary-key

One way from there:
In SQLAlchemy ORM, to map to a specific table, there must be at least one column designated as the primary key column; multi-column composite primary keys are of course also perfectly possible. These columns do not need to be known to the database as primary key columns. The columns only need to behave like a primary key, such as a non-nullable unique identifier for a row.

my code:

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)
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.