I'm trying to construct a query like this:
SELECT "Inventory".item_id, "Inventory".region
FROM "Inventory" ('PLACEHOLDER' = ('$$P_Param$$', '0'))
WHERE "Inventory".region = :region_1
My select statement is adding the HANA placeholders at the end though:
select_stmt = select(
inventory.item_id,
inventory.region
).suffix_with(placeholders).where(inventory.region== 'USA')
SELECT "Inventory".item_id, "Inventory".region
FROM "Inventory"
WHERE "Inventory".region = :region_1 ('PLACEHOLDER' = ('$$P_Param$$', '0'))
How do I suffix the from clause with the placeholders and add the where clause afterwards?
class Inventory(Base):
__tablename__ = 'Inventory'
__table_args__ = {'schema': '_SYS_BIC'}
date = Column(DateTime, primary_key=True)
item_id = Column(Integer, primary_key=True)
region = Column(String)
placeholder = "('PLACEHOLDER' = ('$$P_Param$$', '0'))"
The SAP Hana dialect does not seem to support placeholders.
As you saw suffix_with does exactly what it says, it appends a suffix to the full query.
Without dialect support, you could try using a from_statement with text which will allow to load what you need using your own SQL statements.
Related
I am using Sanic framework with Gino if that matters.
The following works, it generates SQL with check constraint clause:
class Foo(db.Model):
tst2 = db.Column(db.Integer)
__table_args__ = (
sqlalchemy.CheckConstraint('tst2 > 1', name= 'foo'),
)
However, the following does not generate SQL with a check constraint clause. (It does generate all the other necessary SQL successfully):
class Bar(db.Model):
id = db.Column(db.Integer, primary_key=True)
tst2 = db.Column(db.Integer, sqlalchemy.CheckConstraint('tst2 > 1', name='bar2'))
Does Gino have a way to define CheckConstraint in column definitions?
I use column properties to refer to properties of other tables.
I'd like to be able to select arbitrary information from other models indepentend of the declaration order of the models.
Just like sa.orm.relationship declares its relation by strings.
The problem I face is, that property_of_a can not be initialized, because ModelB is not declared at that moment.
Here is a simplified (not working) example.
A working alternative for this example might use sa.ext.associationproxy
I do not think, that I can use association proxies because I'd like to be able to use CONCAT, GROUP_CONCAT and IF-THEN-ELSE Queries.
Is there a way to initialize a sa.select query lazy (for example by strings like sa.orm.relationship)
import sqlalchemy as sa
Base = sa.ext.declarative.declarative_base()
metadata = Base.metadata
class ModelA(Base):
__tablename__ = "model_a_table"
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String(255), nullable=False, unique=True)
model_b_id = sa.Column(sa.ForeignKey('model_b_table.id', ondelete='SET NULL'), index=True)
model_b = sa.orm.relationship("ModelB")
property_of_a = sa.orm.column_property(sa.select([ModelB.name]).where(ModelB.id == model_b_id))
class ModelB(Base):
__tablename__ = "model_b_table"
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String(255), nullable=False, unique=True)
model_a_id = sa.Column(sa.ForeignKey('model_a_table.id', ondelete='SET NULL'), index=True)
model_b = sa.orm.relationship("ModelA")
property_of_b = sa.orm.column_property(sa.select([ModelA.name]).where(ModelB.id == model_a_id))
sa.orm.configure_mappers()
SELECT
maintener.*,
(SELECT COUNT(*)
FROM device d
WHERE d.in_stock_maintener_id = maintener.id) AS in_stock_devices
FROM maintener;
I'm creating a report that show all mainteners but i need to show the number of devices that each one of that mainteners has by looking at the devices model reference in_stock_maintener_id;
I have this models in my persist sqlalchemy.
class Maintener(persist.Base):
__tablename__ = 'maintener'
id = Column(Integer, primary_key=True)
name = Column(String(255))
document_number = Column(String(30))
phone_1 = Column(String(12))
phone_2 = Column(String(12))
email = Column(String(255))
class Device(persist.Base):
__tablename__ = 'device'
id = Column(Integer, primary_key=True)
serial = Column(String(45))
in_stock = Column(SmallInteger)
in_stock_maintener_id = Column(ForeignKey(u'maintener.id'), nullable=True, index=True)
in_stock_maintener = relationship(u'Maintener', lazy='noload', \
primaryjoin='Device.in_stock_maintener_id == Maintener.id')
If anyone could help me, i'll be grateful =)
sq = (
session
.query(func.count())
.select_from(Device)
.filter(Device.in_stock_maintener_id == Maintener.id)
).as_scalar()
q = session.query(Maintener, sq.label('in_stock_devices'))
Query above will return an enumerable of tuple(Maintener, Integer).
If you would like to have columns instead (as per your comment), then you can either specify the columns you want in the query implicitly:
q = session.query(Maintener.id, Maintener.name, sq.label('in_stock_devices'))
or if you would like all columns (as in SELECT *), then you could query the Table instead of the mapped entity:
q = session.query(Maintener.__table__, sq.label('in_stock_devices'))
Above I assumed that you use declarative extension.
Problem
I want to use a COUNT(DISTINCT field) with a GROUP BY clause in Django. As I understand, the COUNT(DISTINCT... can only be achieved by using an extra for the query set.
My simplified model is :
class Site(models.Model):
name = models.CharField(max_length=128, unique=True)
class Application(models.Model):
name = models.CharField(max_length=64)
version = models.CharField(max_length=13, db_index=True)
class User(models.Model):
name = models.CharField(max_length=64)
site = models.ForeignKey(Site, db_index=True)
class Device(models.Model):
imei = models.CharField(max_length=16, unique=True)
applications = models.ManyToManyField(Application, null=True, db_index=True, through='ApplicationUsage')
user = models.ForeignKey(User, null=True, db_index=True)
class ApplicationUsage(models.Model):
activity = models.DateField(db_index=True)
application = models.ForeignKey(Application)
device = models.ForeignKey(Device)
My goal is to have a liste of Site objects with a count of distinct device for each site given an application activity through a time period, something like
stats_site.name deviceCount
ALBI 32
AMPLEPUIS 42
...
I try this code :
qs = models.Site.objects.filter(user__device__applicationusage__activity__range=[startDay, endDay])\
.extra(select={'deviceCount' : 'COUNT(DISTINCT `stats_device`.`id`)'})\
.values('name', 'deviceCount')\
The generated SQL is :
SELECT (COUNT(DISTINCT stats_device.id)) AS deviceCount, stats_site.name
FROM stats_site
INNER JOIN stats_user ON (stats_site.id = stats_user.site_id)
INNER JOIN stats_device ON (stats_user.id = stats_device.user_id)
INNER JOIN stats_applicationusage ON (stats_device.id = stats_applicationusage.device_id)
WHERE stats_applicationusage.activity BETWEEN '2013-07-01' AND '2013-07-03'
And the result is obviously wrong since it lacks the GROUP BY clause, which should be GROUP BY stats_site.name
The problem is: I don't know how to add the correct GROUP BY using the annotate function or other.
Solution
Using distinct=True on the Count function with annotate:
qs = models.Site.objects.filter(habileouser__device__applicationusage__activity__range=[startDay, endDay])\
.annotate(deviceCount=Count('habileouser__device', distinct=True))\
.values('name', 'deviceCount')
The annotate method of a queryset will calculate an aggregate value for each element of the queryset, and when used after a values call will aggregate over the values of the values. I think this should work:
qs = models.Site.objects.filter(
user__device__applicationusage__activity__range=[startDay, endDay]
).values('name').annotate(Count('user__device', distinct=True))
If you have an ordering specified you may need to remove it as discussed here:
https://docs.djangoproject.com/en/dev/topics/db/aggregation/#interaction-with-default-ordering-or-order-by
Right now I'm doing this:
class MyTest(Base):
__tablename__ = 'mytest'
id = Column(Integer, primary_key = True)
name = Column(String(255), nullable=False)
created_at = Column(DateTime)
Base.metadata.create_all(engine)
But in the tutorial, another way is this:
user = Table('user', metadata,
Column('user_id', Integer, primary_key = True),
Column('user_name', String(16), nullable = False),
Column('email_address', String(60)),
Column('password', String(20), nullable = False)
)
Which method should I be using? By the way, I will be using sqlalchemy-migrate, (I don't know if that will change the answer)
If you want to just access the data from the table and want to use SQLAlchemy as a mediator then you have to use TABLE. But if you want to use the each row of the table as an separate object then you have to use declarative base.
Which way you have to use is up to you and how you want to use SQLAlchemy.