Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

method xxx.__table__.create(engine) failed when create view which raise error "sqlalchemy.exc.CompileError: No engine for table 'xxx'" #261

Closed
flyly0755 opened this issue Sep 15, 2023 · 4 comments

Comments

@flyly0755
Copy link

flyly0755 commented Sep 15, 2023

Describe the bug
Use code below to create table and view.
TableTest.table.create(engine) # success create table tableTest
ViewTest.table.create(engine) # raise error sqlalchemy.exc.CompileError: No engine for table 'viewTest'
Base.metadata.create_all(bind=engine) # success create both table tableTest and view viewTest

To Reproduce

from clickhouse_sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column
from sqlalchemy import Integer, String
from clickhouse_sqlalchemy import engines
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy import select
from sqlalchemy_utils import create_view

Base = declarative_base()

class TableTest(Base):
    __tablename__ = 'tabletest'
    id = Column(Integer, primary_key=True)
    testcontent = Column(String)
    remark = Column(String)
    __table_args__ = (
        engines.MergeTree(order_by='id', primary_key='id'),
        {'comment': 'table used for testing'}
    )

viewlist = [] 
viewlist.extend([
    TableTest.id.label('id'),
    TableTest.testcontent.label('testcontent'),
    TableTest.remark.label('remark'),
])
stmt_view = select(viewlist)
cvView = create_view('viewTest', stmt_view, Base.metadata)

class ViewTest(Base):
    __tablename__ = 'viewTest'
    __table__ = cvView
    __table_args__ = {'comment': 'view used for testing'}

# clickhouse machine info
ckuser = "ckuser"
ckpwd = "ckpassword"
ckip = "ckhost"
ckport = "8123"
ckdbname = 'ckdb'

uri = f"clickhouse://{ckuser}:{ckpwd}@" \
      f"{ckip}:{ckport}/{ckdbname}"
engine = create_engine(uri, echo=False)
DBsession = sessionmaker(bind=engine)
session = DBsession()
print(session)
session.execute('SELECT 1')
# TableTest.__table__.create(engine) # success create table tableTest
# ViewTest.__table__.create(engine)  # sqlalchemy.exc.CompileError: No engine for table 'viewTest'
Base.metadata.create_all(bind=engine)  # success create both table tableTest and view viewTest
session.close()

Expected behavior
ViewTest.__table__.create(engine) can create view viewTest successfully.
Maybe xxxt.__table__.create(engine) doesn't support view creation, then how to create one single database view with ORM class?

Versions
python 3.9.11
clickhouse-sqlalchemy==0.2.3
SQLAlchemy==1.4.8
SQLAlchemy-Utils==0.37.8

@flyly0755 flyly0755 changed the title method xxx.__table__.create(engine) failed when create view which raise error "sqlalchemy.exc.CompileError: No engine for table 'viewTest'" method xxx.__table__.create(engine) failed when create view which raise error "sqlalchemy.exc.CompileError: No engine for table 'xxx'" Sep 15, 2023
@xzkostyan
Copy link
Owner

  1. Please, stop using sqlalchemy_utils with this package. There is proper built-in MatView support.
  2. Use clickhouse-sqlalchemy wrappers over sqlalchemy functions instead of pure sqlalchemy calls. make_sesion vs ture sessionmaker
  3. .create() in table and mat view now requires bind argument since SA 2.0
from sqlalchemy import create_engine, Column, MetaData, text

from clickhouse_sqlalchemy import (
    Table, make_session, get_declarative_base, types, engines, MaterializedView, select
)

uri = 'clickhouse://default:@localhost/default'

engine = create_engine(uri)
session = make_session(engine)
metadata = MetaData()

Base = get_declarative_base(metadata=metadata)

class TableTest(Base):
    __tablename__ = 'tabletest'
    
    id = Column(types.Int8, primary_key=True)
    testcontent = Column(types.String)
    remark = Column(types.String)
    
    __table_args__ = (
        engines.MergeTree(order_by='id', primary_key='id'),
        {'comment': 'table used for testing'}
    )

class ViewTest(Base):
    __tablename__ = 'viewTest'

    id = Column(types.Int8, primary_key=True)
    testcontent = Column(types.String)
    remark = Column(types.String)

    __table_args__ = (
        engines.MergeTree(order_by='id', primary_key='id'),
        # Comments are not supported for mat view {'comment': 'view used for testing'}
        # No COMMENT clause here https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view
    )

MatView = MaterializedView(ViewTest, select(
    TableTest.id.label('id'),
    TableTest.testcontent.label('testcontent'),
    TableTest.remark.label('remark'),
))

TableTest.__table__.create(bind=engine)
MatView.create(bind=engine)

@flyly0755
Copy link
Author

flyly0755 commented Feb 18, 2024

@xzkostyan Thank you so much, and I have another doubt, which means only support orm manner to create MaterializedView?
How to create a normal database view with orm manner?

@xzkostyan
Copy link
Owner

I don't understand what do you want.

@flyly0755
Copy link
Author

flyly0755 commented Feb 19, 2024

@xzkostyan
What i mean is there are two kinds of view in clickhouse, one conventional view which not stores data in disk, and MaterializedView which stores data in disk like table data storage.
What I want is to create conventional view instead of MaterializedView, so I can save some disk storage space.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants