[sqlalchemy] Re: anyone have an improved WindowedRangeQuery ?

2014-08-11 Thread Richard Matsen
Try basing the interval query on a correlated subquery, so instead of

q = session.query(
column, 
func.row_number().\
over(order_by=column).\
label('rownum')
).\
from_self(column)


try

subquery = base_query.subquery()q = session.query(
column, 
func.row_number().\
over(order_by=column).\
label('rownum')
).\
join(subquery, subquery.columns[column.name] == column).\
from_self(column)


This should give a SQL statement of

SELECT anon_1.widget_id AS anon_1_widget_id 
FROM (
 SELECT widget.id AS widget_id, row_number() OVER (ORDER BY widget.id) AS 
rownum 
 FROM widget JOIN (
   SELECT widget.id AS id, widget.data AS data 
   FROM widget 
   WHERE widget.id  :id_1) AS anon_2 
   ON anon_2.id = widget.id) AS anon_1 
WHERE rownum % 1000=1


where myQuery is a filtered query on the widget table, in this example I 
used the following to take the first half of the widget table

base_query = session.query(Widget).filter(Widget.id  5000)

For reference, the SQL statement in the original post is

SELECT anon_1.widget_id AS anon_1_widget_id 
FROM (
 SELECT widget.id AS widget_id, row_number() OVER (ORDER BY widget.id) AS 
rownum 
 FROM widget) AS anon_1 
WHERE rownum % 1000=1






On Tuesday, August 5, 2014 12:12:42 AM UTC+1, Jonathan Vanasco wrote:

 I've been working on a migration script, and turned to my trusty friend 
 the WindowedRangeQuery recipe:

   
 https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/WindowedRangeQuery

 I ran into a small problem and hoping someone else may have done this and 
 saved me some work.

 I'm trying to work out some edge cases on a large table, and the default 
 performance is pretty bad in Postgres.

 The two big issues are:

 1. The initial query to create an iterable range is painful.  It takes me 
 about 2 minutes.  This seems to be due to:
 a - loading a lot of data into memory
 b - sequentially scanning the 'id' column.  this function won't use 
 the primary key, or any other index, for id.  it seq scans the whole table.

 2. Window ranges are created for all ids in the table.  If I only want to 
 work on half the records, with a min/max, the 'iterable' query doesn't use 
 the min/max filter values; it generates 100% of potential ranges based on 
 the id, and the filters are only used for the 'where' clause.  

 Has anyone worked out an improved version of this technique, or am I 
 cobbling something together myself?


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] anyone have an improved WindowedRangeQuery ?

2014-08-11 Thread Richard Matsen
Try basing the interval query on a correlated subquery, so instead of

q = session.query(
column, 
func.row_number().\
over(order_by=column).\
label('rownum')
).\
from_self(column)


try

subquery = base_query.subquery()
q = session.query(
column, 
func.row_number().\
over(order_by=column).\
label('rownum')
).\
join(subquery, subquery.columns[column.name] == column).\
from_self(column)


This should give a SQL statement of

SELECT anon_1.widget_id AS anon_1_widget_id 
FROM (
 SELECT widget.id AS widget_id, row_number() OVER (ORDER BY widget.id) AS 
rownum 
 FROM widget JOIN (
   SELECT widget.id AS id, widget.data AS data 
   FROM widget 
   WHERE widget.id  :id_1) AS anon_2 
   ON anon_2.id = widget.id) AS anon_1 
WHERE rownum % 1000=1


where base_query is a filtered query on the widget table, in this example I 
used the following to take the first half of the widget table

base_query = session.query(Widget).filter(Widget.id  5000)

For reference, the SQL statement in the original post is

SELECT anon_1.widget_id AS anon_1_widget_id 
FROM (
 SELECT widget.id AS widget_id, row_number() OVER (ORDER BY widget.id) AS 
rownum 
 FROM widget) AS anon_1 
WHERE rownum % 1000=1


On Tuesday, August 5, 2014 5:15:06 PM UTC+1, Jonathan Vanasco wrote:



 On Monday, August 4, 2014 11:59:36 PM UTC-4, Michael Bayer wrote:


 ah because ROW_NUMBER() needs…the row number!   that is, we need to count 
 the rows between PK values.   Well if you have truly increment-by-one 
 primary keys and that’s what you’re windowing on, you can make that the 
 “rownum”…otherwise, you’re looking for windows of N rows within the whole 
 set of rows.  Counting is necessary, I’m not sure how to force it to use an 
 index-only scan to figure this out.   I haven’t looked into this that 
 deeply. 


 Yeah, I played with it for a while and dug deep into some psql listserves 
 and dba forums trying to trick it.  i might jump on the postgres list for 
 some insight next.  
  

 add a WHERE clause to the query that is selecting the windows, that is 
 instead of: 


 i ended up cobbling one together to do that.  though to eek out a bit of 
 better performance, i used a series of temp tables.  

 i was just wondering if anyone had pulled together a drop-in recipe yet 
 that inspected the base-query for any filters, and pushed that into the 
 'select' that generates the iterables.  


  
  

  



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] anyone have an improved WindowedRangeQuery ?

2014-08-11 Thread Richard Matsen
Can do one better by just passing the filter expression. 

 table_filter = Widget.id  5000

passing table_filter as an optional parameter to column_windows, the 
interval query becomes

q = session.query(
column, 
func.row_number().\
over(order_by=column).\
label('rownum')
)if table_filter is not None:q = 
q.filter(table_filter)
q = q.from_self(column)


This applies the WHERE clause directly without needing a JOIN

The SQL statement with the example table_filter above is

SELECT anon_1.widget_id AS anon_1_widget_id 
FROM (
 SELECT widget.id AS widget_id, row_number() OVER (ORDER BY widget.id) AS 
rownum 
 FROM widget
 WHERE widget.id  :id_1) AS anon_1 
WHERE rownum % 1000=1


or if table_filter is None:

SELECT anon_1.widget_id AS anon_1_widget_id 
FROM (
 SELECT widget.id AS widget_id, row_number() OVER (ORDER BY widget.id) AS 
rownum 
 FROM widget) AS anon_1 
WHERE rownum % 1000=1


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] Help producing query, making use of nested joins

2014-08-11 Thread Michael Bayer
For nesting the joins you have to use the join() construct manually, your 
example is pretty verbose there, here's a shorter example.Note that 
SQLAlchemy has two join() functions - one is sqlalchemy.sql.join, the other 
is sqlalchemy.orm.join.  The main thing you get from orm.join is that you can 
use a relationship as the ON clause as in the example below.


from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.orm import Session, relationship, join
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class A(Base):
__tablename__ = 'a'

id = Column(Integer, primary_key=True)
bs = relationship(B)


class B(Base):
__tablename__ = 'b'

id = Column(Integer, primary_key=True)
a_id = Column(Integer, ForeignKey('a.id'))
cs = relationship(C)


class C(Base):
__tablename__ = 'c'

id = Column(Integer, primary_key=True)
b_id = Column(Integer, ForeignKey('b.id'))

sess = Session()

j1 = join(B, C, B.cs)

q = sess.query(A).join(j1)

print q


On Aug 10, 2014, at 3:13 AM, mike waites mikey.wai...@googlemail.com wrote:

 Hey!
 
 I not sure if this is entirely possible in SQA and i'm more than open to 
 suggestions for ways to improve the query itself but im looking to produce 
 the following.
 
 https://gist.github.com/mikeywaites/9e7290eaddcf003e4407
 
 The thing in particular i'm having trouble with is the syntax for the nested 
 joins.  The below doesn't work but i thought it would serve as a start point 
 for anyone able to help.
 
 https://gist.github.com/mikeywaites/59476c0fd91301b53697
 
 Some related material i've found:
 
 https://bitbucket.org/zzzeek/sqlalchemy/issue/2120/support-nesting-of-joins-with-joined-eager
 http://docs.sqlalchemy.org/en/rel_0_9/changelog/migration_09.html#right-nested-inner-joins-available-in-joined-eager-loads
 
 So mostly its just the syntax of the nested joins im struggling with at the 
 moment.  I can't quite nail the alias + nesting combinations!
 
 Again, any suggestions on improving the query overall are more than welcome 
 too!!
 
 Thanks!
 
 
 
 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to sqlalchemy+unsubscr...@googlegroups.com.
 To post to this group, send email to sqlalchemy@googlegroups.com.
 Visit this group at http://groups.google.com/group/sqlalchemy.
 For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] Use a string or reference in ForeignKey?

2014-08-11 Thread Michael Bayer

On Aug 10, 2014, at 2:52 PM, alchemy1 veerukrish...@hotmail.com wrote:

 I see that in ForeignKey I can use either a string or reference, so 
 ForeignKey(MyModel.id) or ForeignKey('my_model.id'). Any advantage to using 
 one or the other? What's the recommended approach?

whichever one is more convenient to the style in which you are setting up table 
metadata is fine.   The advantage of the string is that the target table 
doesn't have to exist at the point at which you define the ForeignKey, which 
eliminates the need to use imports for tables set up in other modules.

 
 When using the string way, is it recommended to use the model name like 
 'MyModel.id' or table name like 'my_model.id'?

the strings here are intercepted by ForeignKey() which works at the level of 
SQLAlchemy Core, that is, it doesn't know anything about mapped classes, just 
table names that are present in the same MetaData collection.So table 
names.The class names won't resolve right now (could be something we add 
later though).

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] self-referential relationship and aliases

2014-08-11 Thread dweitzenfeld
I've got the expression part of the hybrid properties working now, using an 
alias:

@friend_code_usage_count.expression
def friend_code_usage_count(cls):
alias = aliased(AffinionCode)
return select([func.count(alias.Rtid)]). \
where(alias.PromoCode == 
cls.ReferAFriendCode).label('friend_code_usage_count')

​

I was going to ask how to add aliasing to the relationship definitions, but 
it seems like I don't have to.  Awesome, thanks for your help. 



On Sunday, August 10, 2014 7:08:43 PM UTC-5, Michael Bayer wrote:

 it seems like you might want to make use of aliased() in those 
 @hybrid_properties you have; if you do an equijoin from 
 AffinionCode.something == cls.somethingelse, “cls” here is AffinionCode 
 again.   One side should be an aliased() object.





 On Aug 10, 2014, at 8:01 PM, dweitzenfeld dweitz...@gmail.com 
 javascript: wrote:


 I'm having trouble getting a self-referential table to alias correctly.  
 In the example below, Jack was given a family code of 'FOO.'  He shares 
 this with his family member Jill, who enters it as her PromoCode.




 RtidPromoCodeFamilyCodeJackBARFOOJillFOO

 ​

 This is my sqlalchemy class for the table:

 class AffinionCode(MssqlBase):
 __tablename__ = AffinionCodes
 Rtid = Column(String, ForeignKey('MemberFacts.Rtid'), primary_key=True)
 PromoCode = Column(String)
 FamilyCode = Column(String)
 ReferAFriendCode = Column(String)
 family_code_usages = relationship(AffinionCode,
   primaryjoin=PromoCode == FamilyCode,
   foreign_keys=FamilyCode,
   remote_side=PromoCode,
   backref='family_source')
 friend_code_usages = relationship(AffinionCode,
   primaryjoin=PromoCode == 
 ReferAFriendCode,
   foreign_keys=ReferAFriendCode,
   remote_side=PromoCode,
   backref='friend_source')

 @hybrid_property
 def family_code_usage_count(self):
 return len([_ for _ in self.family_code_usages])

 @family_code_usage_count.expression
 def family_code_usage_count(cls):
 return select([func.count(AffinionCode.Rtid)]). \
 where(AffinionCode.PromoCode == 
 cls.FamilyCode).label('family_code_usage_count')

 @hybrid_property
 def friend_code_usage_count(self):
 return len([_ for _ in self.friend_code_usages])

 @friend_code_usage_count.expression
 def friend_code_usage_count(cls):
 return select([func.count(AffinionCode.Rtid)]). \
 where(AffinionCode.PromoCode == 
 cls.ReferAFriendCode).label('friend_code_usage_count')

 ​


 The problem is that this is producing queries like:

 SELECT TOP 10 [AffinionCodes]. [Rtid] AS [AffinionCodes_Rtid],
[AffinionCodes]. [PromoCode] AS [AffinionCodes_PromoCode],
[AffinionCodes]. [FamilyCode] AS [AffinionCodes_FamilyCode],
[AffinionCodes]. [ReferAFriendCode] AS 
 [AffinionCodes_ReferAFriendCode],
(SELECT COUNT([AffinionCodes]. [Rtid]) AS count_1
 FROM [AffinionCodes] 
 WHERE [AffinionCodes]. [PromoCode] = [AffinionCodes]. [FamilyCode]) 
 AS family_code_usagesFROM [AffinionCodes]WHERE (SELECT COUNT([AffinionCodes]. 
 [Rtid]) AS count_1
FROM [AffinionCodes] AS [AffinionCodes]
WHERE [AffinionCodes]. [PromoCode] = [AffinionCodes]. [FamilyCode])  
 1;

 ​

 when I need it alias, like so:

 SELECT TOP 10 [AffinionCodes]. [Rtid] AS [AffinionCodes_Rtid],
[AffinionCodes]. [PromoCode] AS [AffinionCodes_PromoCode],
[AffinionCodes]. [FamilyCode] AS [AffinionCodes_FamilyCode],
[AffinionCodes]. [ReferAFriendCode] AS 
 [AffinionCodes_ReferAFriendCode],
(SELECT COUNT([AffinionCodes1]. [Rtid]) AS count_1
 FROM [AffinionCodes] AS [AffinionCodes1]
 WHERE [AffinionCodes1]. [PromoCode] = [AffinionCodes]. [FamilyCode]) 
 AS family_code_usagesFROM [AffinionCodes]WHERE (SELECT 
 COUNT([AffinionCodes1]. [Rtid]) AS count_1
FROM [AffinionCodes] AS [AffinionCodes1]
WHERE [AffinionCodes1]. [PromoCode] = [AffinionCodes]. [FamilyCode])  
 1;

 ​

 Any help would be greatly appreciated, thanks!







 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email tosqlalchemy+...@googlegroups.com javascript:.
 To post to this group, send email to sqlal...@googlegroups.com 
 javascript:.
 Visit this group at http://groups.google.com/group/sqlalchemy.
 For more options, visit https://groups.google.com/d/optout.




-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to 

Re: [sqlalchemy] self-referential relationship and aliases

2014-08-11 Thread dweitzenfeld
I do have a follow up, actually.

If I wanted to make friend_code_usage_count a column property so that it 
was always loaded with the object, how would I do that? 
It doesn't look like I can add 

alias = aliased(AffinionCode)

within the class definition. Where/how would I define the alias?  


On Monday, August 11, 2014 12:56:01 PM UTC-5, dweitzenfeld wrote:

 I've got the expression part of the hybrid properties working now, using 
 an alias:

 @friend_code_usage_count.expression
 def friend_code_usage_count(cls):
 alias = aliased(AffinionCode)
 return select([func.count(alias.Rtid)]). \
 where(alias.PromoCode == 
 cls.ReferAFriendCode).label('friend_code_usage_count')

 ​

 I was going to ask how to add aliasing to the relationship definitions, 
 but it seems like I don't have to.  Awesome, thanks for your help. 



 On Sunday, August 10, 2014 7:08:43 PM UTC-5, Michael Bayer wrote:

 it seems like you might want to make use of aliased() in those 
 @hybrid_properties you have; if you do an equijoin from 
 AffinionCode.something == cls.somethingelse, “cls” here is AffinionCode 
 again.   One side should be an aliased() object.





 On Aug 10, 2014, at 8:01 PM, dweitzenfeld dweitz...@gmail.com wrote:


 I'm having trouble getting a self-referential table to alias correctly.  
 In the example below, Jack was given a family code of 'FOO.'  He shares 
 this with his family member Jill, who enters it as her PromoCode.




 RtidPromoCodeFamilyCodeJackBARFOOJillFOO

 ​

 This is my sqlalchemy class for the table:

 class AffinionCode(MssqlBase):
 __tablename__ = AffinionCodes
 Rtid = Column(String, ForeignKey('MemberFacts.Rtid'), primary_key=True)
 PromoCode = Column(String)
 FamilyCode = Column(String)
 ReferAFriendCode = Column(String)
 family_code_usages = relationship(AffinionCode,
   primaryjoin=PromoCode == FamilyCode,
   foreign_keys=FamilyCode,
   remote_side=PromoCode,
   backref='family_source')
 friend_code_usages = relationship(AffinionCode,
   primaryjoin=PromoCode == 
 ReferAFriendCode,
   foreign_keys=ReferAFriendCode,
   remote_side=PromoCode,
   backref='friend_source')

 @hybrid_property
 def family_code_usage_count(self):
 return len([_ for _ in self.family_code_usages])

 @family_code_usage_count.expression
 def family_code_usage_count(cls):
 return select([func.count(AffinionCode.Rtid)]). \
 where(AffinionCode.PromoCode == 
 cls.FamilyCode).label('family_code_usage_count')

 @hybrid_property
 def friend_code_usage_count(self):
 return len([_ for _ in self.friend_code_usages])

 @friend_code_usage_count.expression
 def friend_code_usage_count(cls):
 return select([func.count(AffinionCode.Rtid)]). \
 where(AffinionCode.PromoCode == 
 cls.ReferAFriendCode).label('friend_code_usage_count')

 ​


 The problem is that this is producing queries like:

 SELECT TOP 10 [AffinionCodes]. [Rtid] AS [AffinionCodes_Rtid],
[AffinionCodes]. [PromoCode] AS [AffinionCodes_PromoCode],
[AffinionCodes]. [FamilyCode] AS [AffinionCodes_FamilyCode],
[AffinionCodes]. [ReferAFriendCode] AS 
 [AffinionCodes_ReferAFriendCode],
(SELECT COUNT([AffinionCodes]. [Rtid]) AS count_1
 FROM [AffinionCodes] 
 WHERE [AffinionCodes]. [PromoCode] = [AffinionCodes]. [FamilyCode]) 
 AS family_code_usagesFROM [AffinionCodes]WHERE (SELECT 
 COUNT([AffinionCodes]. [Rtid]) AS count_1
FROM [AffinionCodes] AS [AffinionCodes]
WHERE [AffinionCodes]. [PromoCode] = [AffinionCodes]. [FamilyCode])  
 1;

 ​

 when I need it alias, like so:

 SELECT TOP 10 [AffinionCodes]. [Rtid] AS [AffinionCodes_Rtid],
[AffinionCodes]. [PromoCode] AS [AffinionCodes_PromoCode],
[AffinionCodes]. [FamilyCode] AS [AffinionCodes_FamilyCode],
[AffinionCodes]. [ReferAFriendCode] AS 
 [AffinionCodes_ReferAFriendCode],
(SELECT COUNT([AffinionCodes1]. [Rtid]) AS count_1
 FROM [AffinionCodes] AS [AffinionCodes1]
 WHERE [AffinionCodes1]. [PromoCode] = [AffinionCodes]. [FamilyCode]) 
 AS family_code_usagesFROM [AffinionCodes]WHERE (SELECT 
 COUNT([AffinionCodes1]. [Rtid]) AS count_1
FROM [AffinionCodes] AS [AffinionCodes1]
WHERE [AffinionCodes1]. [PromoCode] = [AffinionCodes]. [FamilyCode]) 
  1;

 ​

 Any help would be greatly appreciated, thanks!







 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email tosqlalchemy+...@googlegroups.com.
 To post to this group, send email to 

Re: [sqlalchemy] self-referential relationship and aliases

2014-08-11 Thread Mike Bayer
For a fancy column_property like that you likely need to define it after
the fact and attach it to the class.   There's some new features I have
in the works for 1.0 to make that easier.

The general idea is:

class MyClass(Base):
   # ...

alias = aliased(MyClass)
stmt = select([alias.foo]).where(alias.id ==
MyClass.other_id).correlate(MyClass).as_scalar()
MyClass.some_prop = column_property(stmt)




On 08/11/2014 02:03 PM, dweitzenfeld wrote:
 I do have a follow up, actually.

 If I wanted to make friend_code_usage_count a column property so that
 it was always loaded with the object, how would I do that? 
 It doesn't look like I can add 

 alias = aliased(AffinionCode)

 within the class definition. Where/how would I define the alias?  


 On Monday, August 11, 2014 12:56:01 PM UTC-5, dweitzenfeld wrote:

 I've got the expression part of the hybrid properties working now,
 using an alias:

 |@friend_code_usage_count.expression
 def friend_code_usage_count(cls):
 alias = aliased(AffinionCode)
 return select([func.count(alias.Rtid)]). \
 where(alias.PromoCode == 
 cls.ReferAFriendCode).label('friend_code_usage_count')
 |

 ​

 I was going to ask how to add aliasing to the relationship
 definitions, but it seems like I don't have to.  Awesome, thanks
 for your help. 



 On Sunday, August 10, 2014 7:08:43 PM UTC-5, Michael Bayer wrote:

 it seems like you might want to make use of aliased() in those
 @hybrid_properties you have; if you do an equijoin from
 AffinionCode.something == cls.somethingelse, “cls” here is
 AffinionCode again.   One side should be an aliased() object.





 On Aug 10, 2014, at 8:01 PM, dweitzenfeld
 dweitz...@gmail.com wrote:


 I'm having trouble getting a self-referential table to alias
 correctly.  
 In the example below, Jack was given a family code of 'FOO.'
  He shares this with his family member Jill, who enters it as
 her PromoCode.




 Rtid PromoCode   FamilyCode
 Jack BAR FOO
 Jill FOO 


 ​

 This is my sqlalchemy class for the table:

 |class AffinionCode(MssqlBase):
 __tablename__ = AffinionCodes
 Rtid = Column(String, ForeignKey('MemberFacts.Rtid'), 
 primary_key=True)
 PromoCode = Column(String)
 FamilyCode = Column(String)
 ReferAFriendCode = Column(String)
 family_code_usages = relationship(AffinionCode,
   primaryjoin=PromoCode == 
 FamilyCode,
   foreign_keys=FamilyCode,
   remote_side=PromoCode,
   backref='family_source')
 friend_code_usages = relationship(AffinionCode,
   primaryjoin=PromoCode == 
 ReferAFriendCode,
   foreign_keys=ReferAFriendCode,
   remote_side=PromoCode,
   backref='friend_source')

 @hybrid_property
 def family_code_usage_count(self):
 return len([_ for _ in self.family_code_usages])

 @family_code_usage_count.expression
 def family_code_usage_count(cls):
 return select([func.count(AffinionCode.Rtid)]). \
 where(AffinionCode.PromoCode == 
 cls.FamilyCode).label('family_code_usage_count')

 @hybrid_property
 def friend_code_usage_count(self):
 return len([_ for _ in self.friend_code_usages])

 @friend_code_usage_count.expression
 def friend_code_usage_count(cls):
 return select([func.count(AffinionCode.Rtid)]). \
 where(AffinionCode.PromoCode == 
 cls.ReferAFriendCode).label('friend_code_usage_count')
 |
 ​


 The problem is that this is producing queries like:
 |SELECT TOP 10 [AffinionCodes]. [Rtid] AS [AffinionCodes_Rtid],
[AffinionCodes]. [PromoCode] AS [AffinionCodes_PromoCode],
[AffinionCodes]. [FamilyCode] AS [AffinionCodes_FamilyCode],
[AffinionCodes]. [ReferAFriendCode] AS 
 [AffinionCodes_ReferAFriendCode],
(SELECT COUNT([AffinionCodes]. [Rtid]) AS count_1
 FROM [AffinionCodes] 
 WHERE [AffinionCodes]. [PromoCode] = [AffinionCodes]. 
 [FamilyCode]) AS family_code_usages
 FROM [AffinionCodes]
 WHERE (SELECT COUNT([AffinionCodes]. [Rtid]) AS count_1
FROM [AffinionCodes] AS [AffinionCodes]
WHERE [AffinionCodes]. [PromoCode] = [AffinionCodes]. 
 [FamilyCode])  1;
 |
   

Re: [sqlalchemy] self-referential relationship and aliases

2014-08-11 Thread dweitzenfeld
cool, thanks again. 

On Monday, August 11, 2014 1:19:30 PM UTC-5, Michael Bayer wrote:

  For a fancy column_property like that you likely need to define it after 
 the fact and attach it to the class.   There's some new features I have in 
 the works for 1.0 to make that easier.

 The general idea is:

 class MyClass(Base):
# ...

 alias = aliased(MyClass)
 stmt = select([alias.foo]).where(alias.id == 
 MyClass.other_id).correlate(MyClass).as_scalar()
 MyClass.some_prop = column_property(stmt)




 On 08/11/2014 02:03 PM, dweitzenfeld wrote:
  
 I do have a follow up, actually. 

  If I wanted to make friend_code_usage_count a column property so that it 
 was always loaded with the object, how would I do that? 
 It doesn't look like I can add 

  alias = aliased(AffinionCode)
  
 within the class definition. Where/how would I define the alias?  


 On Monday, August 11, 2014 12:56:01 PM UTC-5, dweitzenfeld wrote: 

  I've got the expression part of the hybrid properties working now, 
 using an alias:

  @friend_code_usage_count.expression
 def friend_code_usage_count(cls):
 alias = aliased(AffinionCode)
 return select([func.count(alias.Rtid)]). \
 where(alias.PromoCode == 
 cls.ReferAFriendCode).label('friend_code_usage_count')

 ​
  
  I was going to ask how to add aliasing to the relationship definitions, 
 but it seems like I don't have to.  Awesome, thanks for your help. 

  

 On Sunday, August 10, 2014 7:08:43 PM UTC-5, Michael Bayer wrote: 

 it seems like you might want to make use of aliased() in those 
 @hybrid_properties you have; if you do an equijoin from 
 AffinionCode.something == cls.somethingelse, “cls” here is AffinionCode 
 again.   One side should be an aliased() object. 

  

  
  
  On Aug 10, 2014, at 8:01 PM, dweitzenfeld dweitz...@gmail.com wrote:

  
 I'm having trouble getting a self-referential table to alias correctly.  
 In the example below, Jack was given a family code of 'FOO.'  He shares 
 this with his family member Jill, who enters it as her PromoCode.
  
  
  
  
   Rtid PromoCode FamilyCode  Jack BAR FOO  Jill FOO 
   
  ​
  
  This is my sqlalchemy class for the table:

  class AffinionCode(MssqlBase):
 __tablename__ = AffinionCodes
 Rtid = Column(String, ForeignKey('MemberFacts.Rtid'), primary_key=True)
 PromoCode = Column(String)
 FamilyCode = Column(String)
 ReferAFriendCode = Column(String)
 family_code_usages = relationship(AffinionCode,
   primaryjoin=PromoCode == FamilyCode,
   foreign_keys=FamilyCode,
   remote_side=PromoCode,
   backref='family_source')
 friend_code_usages = relationship(AffinionCode,
   primaryjoin=PromoCode == 
 ReferAFriendCode,
   foreign_keys=ReferAFriendCode,
   remote_side=PromoCode,
   backref='friend_source')

 @hybrid_property
 def family_code_usage_count(self):
 return len([_ for _ in self.family_code_usages])

 @family_code_usage_count.expression
 def family_code_usage_count(cls):
 return select([func.count(AffinionCode.Rtid)]). \
 where(AffinionCode.PromoCode == 
 cls.FamilyCode).label('family_code_usage_count')

 @hybrid_property
 def friend_code_usage_count(self):
 return len([_ for _ in self.friend_code_usages])

 @friend_code_usage_count.expression
 def friend_code_usage_count(cls):
 return select([func.count(AffinionCode.Rtid)]). \
 where(AffinionCode.PromoCode == 
 cls.ReferAFriendCode).label('friend_code_usage_count')

 ​
  
  
  The problem is that this is producing queries like:
  
 SELECT TOP 10 [AffinionCodes]. [Rtid] AS [AffinionCodes_Rtid],
[AffinionCodes]. [PromoCode] AS [AffinionCodes_PromoCode],
[AffinionCodes]. [FamilyCode] AS [AffinionCodes_FamilyCode],
[AffinionCodes]. [ReferAFriendCode] AS 
 [AffinionCodes_ReferAFriendCode],
(SELECT COUNT([AffinionCodes]. [Rtid]) AS count_1
 FROM [AffinionCodes] 
 WHERE [AffinionCodes]. [PromoCode] = [AffinionCodes]. [FamilyCode]) 
 AS family_code_usagesFROM [AffinionCodes]WHERE (SELECT 
 COUNT([AffinionCodes]. [Rtid]) AS count_1
FROM [AffinionCodes] AS [AffinionCodes]
WHERE [AffinionCodes]. [PromoCode] = [AffinionCodes]. [FamilyCode]) 
  1;

 ​
  
  when I need it alias, like so:
  
 SELECT TOP 10 [AffinionCodes]. [Rtid] AS [AffinionCodes_Rtid],
[AffinionCodes]. [PromoCode] AS [AffinionCodes_PromoCode],
[AffinionCodes]. [FamilyCode] AS [AffinionCodes_FamilyCode],
[AffinionCodes]. [ReferAFriendCode] AS 
 [AffinionCodes_ReferAFriendCode],
(SELECT COUNT([AffinionCodes1]. [Rtid]) AS count_1
 FROM [AffinionCodes] AS [AffinionCodes1]

[sqlalchemy] Trying to get tables to be created by unit tests

2014-08-11 Thread alchemy1
I have combined several examples I've found to try to get the 
'transactional-style' of unit tests to work, where you roll back the 
database after each test. However when I run this, the test fails when 
trying to insert the object with DBSession.add, complaining that the tables 
don't exist. I thought Base.metadata.create_all(connection) would create 
the tables? I'd like to create the tables within the setup_module and roll 
it back in teardown_module so that the testdb database always goes back to 
being empty. This is to ensure that the tests are always running against a 
known state. (Start with empty db, create the tables, do the tests, then 
empty the db)

Also, since a lot of copy-pasting was involved in creating this, could you 
please take a look and see what isn't necessary? I'm just trying to do 
simple tests (in Pyramid). For example is self.session = Session(connection) 
required? And is using the global variables the way I am a good way of 
doing it? Quite new to this so just trying to learn the best practices.


from sqlalchemy.engine import create_engine
from sqlalchemy.orm.session import Session

from pyramid import testing

from .models import Base
from .models import DBSession

transaction = None
connection = None
engine = None


def setup_module():
global transaction, connection, engine

engine = create_engine(
'postgresql+psycopg2://username:password@host:5432/testdb')
DBSession.configure(bind=engine)
connection = engine.connect()
transaction = connection.begin()
Base.metadata.create_all(connection)


def teardown_module():
global transaction, connection, engine
transaction.rollback()
connection.close()
engine.dispose()


class DatabaseTest(object):

def setup(self):
self.__transaction = connection.begin_nested()
self.session = Session(connection)

def teardown(self):
self.session.close()
self.__transaction.rollback()


class TestCustom(DatabaseTest):

def test_passing_view(self):
from .models import MyModel
model = MyModel(name='one', value=55)
DBSession.add(model)

from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
assert info['one'].name == 'one'





-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] Trying to get tables to be created by unit tests

2014-08-11 Thread Mike Bayer

On 08/11/2014 04:37 PM, alchemy1 wrote:
 I have combined several examples I've found to try to get the
 'transactional-style' of unit tests to work, where you roll back the
 database after each test. However when I run this, the test fails when
 trying to insert the object with DBSession.add, complaining that the
 tables don't exist.

are you setting up the Connection in DBSession?   I see you doing
something with self.session, but that is not the same session as
DBSession.   If DBSession is a scoped session you'd want to say
DBSession(bind=connection) for each test.


 I thought Base.metadata.create_all(connection) would create the
 tables? I'd like to create the tables within the setup_module and roll
 it back in teardown_module so that the testdb database always goes
 back to being empty. This is to ensure that the tests are always
 running against a known state. (Start with empty db, create the
 tables, do the tests, then empty the db)

 Also, since a lot of copy-pasting was involved in creating this, could
 you please take a look and see what isn't necessary? I'm just trying
 to do simple tests (in Pyramid). For example is |self.session
 =Session(connection)required? And is using the global variables the
 way I am a good way of doing it? Quite new to this so just trying to
 learn the best practices.
 |

 |
 fromsqlalchemy.engine importcreate_engine
 fromsqlalchemy.orm.session importSession

 frompyramid importtesting

 from.models importBase
 from.models importDBSession

 transaction =None
 connection =None
 engine =None


 defsetup_module():
 globaltransaction,connection,engine

 engine
 =create_engine('postgresql+psycopg2://username:password@host:5432/testdb')
 DBSession.configure(bind=engine)
 connection =engine.connect()
 transaction =connection.begin()
 Base.metadata.create_all(connection)


 defteardown_module():
 globaltransaction,connection,engine
 transaction.rollback()
 connection.close()
 engine.dispose()


 classDatabaseTest(object):

 defsetup(self):
 self.__transaction =connection.begin_nested()
 self.session =Session(connection)

 defteardown(self):
 self.session.close()
 self.__transaction.rollback()


 classTestCustom(DatabaseTest):

 deftest_passing_view(self):
 from.models importMyModel
 model =MyModel(name='one',value=55)
 DBSession.add(model)

 from.views importmy_view
 request =testing.DummyRequest()
 info =my_view(request)
 assertinfo['one'].name =='one'
 |





 -- 
 You received this message because you are subscribed to the Google
 Groups sqlalchemy group.
 To unsubscribe from this group and stop receiving emails from it, send
 an email to sqlalchemy+unsubscr...@googlegroups.com
 mailto:sqlalchemy+unsubscr...@googlegroups.com.
 To post to this group, send email to sqlalchemy@googlegroups.com
 mailto:sqlalchemy@googlegroups.com.
 Visit this group at http://groups.google.com/group/sqlalchemy.
 For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.