Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sqlalchemy if table does not exist

I've managed to figure out what I intended to do. I used engine.dialect.has_table(engine, Variable_tableName) to check if the database has the table inside. IF it doesn't, then it will proceed to create a table in the database.

Sample code:

engine = create_engine("sqlite:///myexample.db")  # Access the DB Engine
if not engine.dialect.has_table(engine, Variable_tableName):  # If table don't exist, Create.
    metadata = MetaData(engine)
    # Create a table with the appropriate Columns
    Table(Variable_tableName, metadata,
          Column('Id', Integer, primary_key=True, nullable=False), 
          Column('Date', Date), Column('Country', String),
          Column('Brand', String), Column('Price', Float),
    # Implement the creation
    metadata.create_all()

This seems to be giving me what i'm looking for.


Note that in 'Base.metadata' documentation it states about create_all:

Conditional by default, will not attempt to recreate tables already present in the target database.

And if you can see that create_all takes these arguments: create_all(self, bind=None, tables=None, checkfirst=True), and according to documentation:

Defaults to True, don't issue CREATEs for tables already present in the target database.

So if I understand your question correctly, you can just skip the condition.


For those who define the table first in some models.table file, among other tables. This is a code snippet for finding the class that represents the table we want to create ( so later we can use the same code to just query it )

But together with the if written above, I still run the code with checkfirst=True

ORMTable.__table__.create(bind=engine, checkfirst=True)

models.table

class TableA(Base):
class TableB(Base):
class NewTableC(Base):

   id = Column('id', Text)
   name = Column('name', Text)

form

Then in the form action file:

engine = create_engine("sqlite:///myexample.db")
if not engine.dialect.has_table(engine, table_name):
   # Added to models.tables the new table I needed ( format Table as written above )
   table_models = importlib.import_module('models.tables')

   # Grab the class that represents the new table
   # table_name = 'NewTableC'
   ORMTable = getattr(table_models, table_name)            

   # checkfirst=True to make sure it doesn't exists
   ORMTable.__table__.create(bind=engine, checkfirst=True)

The accepted answer prints a warning that engine.dialect.has_table() is only for internal use and not part of the public API. The message suggests this as an alternative, which works for me:

import os
import sqlalchemy

# Set up a connection to a SQLite3 DB
test_db = os.getcwd() + "/test.sqlite"
db_connection_string = "sqlite:///" + test_db
engine = create_engine(db_connection_string)

# The recommended way to check for existence
sqlalchemy.inspect(engine).has_table("BOOKS")

See also the SQL Alchemy docs.


engine.dialect.has_table does not work for me on cx_oracle. I am getting AttributeError: 'OracleDialect_cx_oracle' object has no attribute 'default_schema_name'

I wrote a workaround function:

from sqlalchemy.engine.base import Engine  
def orcl_tab_or_view_exists(in_engine: Engine, in_object: str,  in_object_name: str,)-> bool:
    """Checks if Oracle table exists in current in_engine connection

    in_object: 'table' | 'view'

    in_object_name: table_name | view_name
      """
    obj_query = """SELECT {o}_name FROM all_{o}s WHERE owner = SYS_CONTEXT ('userenv', 'current_schema') AND {o}_name = '{on}'
    """.format(o=in_object, on=in_object_name.upper())
    with in_engine.connect() as connection:
        result = connection.execute(obj_query)
    return len(list(result)) > 0