Re: [sqlalchemy] Re: Aliasing a constant within a recursive CTE

2012-07-10 Thread Russell Warren
I now have a less klugey (no strings) implementation that I came to after
circling back to the the recursive CTE example in the docs, but is
structured in a way that I can wrap my head around a lot better:

import sqlalchemy as sa
#initialize a recursive CTE construct using the non-recursive term...
cte_init = sa.\
select([sa.literal(0).label(x), ]).\
cte(recursive = True, name = cte)
#Make an alias that can be thought of as the CTE's working table...
# - this is *mandatory* for SQLAlchemy to build the query correctly,
#   even though the alias itself is not required in this particular
#   resulting query (is it ever needed?)
cte_working = cte_init.alias(working)
cte_recurs = sa.\
select([cte_working.c.x + 1, ]).\
where(cte_working.c.x  10)
cte = cte_init.union_all(cte_recurs)
statement = sa.select([cte.c.x, ])
print statement

which yields:

WITH RECURSIVE cte(x) AS
(SELECT :param_1 AS x UNION ALL SELECT working.x + :x_1 AS anon_1
FROM cte AS working
WHERE working.x  :x_2)
 SELECT cte.x
FROM cte
 statement.compile().params
{u'x_2': 10, u'param_1': 0, u'x_1': 1}

which works perfectly in PostgreSQL:

 print conn.execute(statement).fetchall()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

As per the comments in the code, the alias is absolutely required (it gets
mangled without the alias), but is seemingly pointless in the resulting
SQL.  Of course, it wouldn't be that surprising if it were required for a
more complex CTE (or strict SQL compliance?), but I'm wondering if it is
just needed for the underlying query generator?

Anyway - with this more closely matching the example in the docs I wonder
what the heck my problem was originally.

That said, it might be useful to structure the documented CTE examples in a
way like I've done above (init, working, recursive, and final cte) as an
easier introduction to how to use CTEs in SQLAlchemy (at least for the
recursive ones).  Hopefully it helps someone else.

Russ

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] help with hierarchy

2012-07-10 Thread Sebastian Elner

Hello,

I need some hints on how to build a query on a data structure which 
turned out to be a hierarchy. Please find the picture of the EER diagram 
attached. I want to get all note entities for a given project with 
their corresponding project, shots and assets. Something like:

(project1, shot1, asset1, note1)
(project1, shot1, asset1, note2)
(project1, shot1, asset2, note1)

No problem with joins.

but I also want to get also:
(project1, None, None, note1)
(project1, Shot1, None, note1)

How is this possible with one query?

Cheers

Sebastian

--
Sebastian Elsner-pipeline td   -   r i s e |  fx

t:  +49 30 20180300 sebast...@risefx.com
  www.risefx.com

r i s e |  fx  GmbH
Schlesische Strasse 28 Aufgang B, 10997 Berlin
Geschäftsführer: Sven Pannicke, Robert Pinnow

Handelsregister Berlin HRB 106667 B

--
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

attachment: hierarchy.png

Re: [sqlalchemy] Problem with Association Object mapping

2012-07-10 Thread Jules Stevenson
Seems I got the append wrong, the below works fine, thanks again for your
help.

due_con.due_user = c.user
contact.due_dates.append(due_con)


On Tue, Jul 10, 2012 at 8:46 AM, Jules Stevenson
droolz...@googlemail.comwrote:

 Hi Michael,

 Yes, I am doing this:

 due_con = model.ArkContactDueDate()
 due_con.modded =
 arkUtils.process_date(field_dataList['duecontact'])
 due_con.contact = contact

 #todo: cannot append since it gives a duff default error message.
 #have triple checked against docs and DB looks sound, so not sure..
 c.user.due_contacts.append(due_con)

 ...but still get the error - is there anything else I can look into? Thank
 you for getting back to me, the level of support you give is outstanding.

 Jules

 On Mon, Jul 9, 2012 at 11:40 PM, Michael Bayer 
 mike...@zzzcomputing.comwrote:


 On Jul 9, 2012, at 6:08 PM, Jules Stevenson wrote:

 Hi All,

 I'm trying to put together an Association Object mapping within a pylons
 app, but am getting the following error:

 OperationalError: (OperationalError) (1364, Field 'user_id' doesn't have
 a default value) 'INSERT INTO contact_duedate_user_association
 (contact_id, modded) VALUES (%s, %s)' (209L, datetime.date(2012, 7, 18))

 As far as I can tell I've followed the recomendations in the association
 object help and am somehwta stumped as to what is causing the error. The
 classes are non-declarative, and are as follows (and if the formatting
 holds up the relevant bits should be in bold). Any help enormously
 appreciated.


 mapping looks fine, you'd need to ensure every ArkContactDueDate you add
 to the Session is associated with a User also in that session.
  single_parent=True should not be needed here.





 contacts_table = sa.Table('contacts', meta.metadata,
 sa.Column('id', sa.types.Integer, primary_key=True),
 sa.Column('project_id', sa.types.Integer, sa.ForeignKey('projects.id
 ')),
 sa.Column('client_id', sa.types.Integer, sa.ForeignKey('clients.id
 ')),
 sa.Column('firstname',sa.types.String(length=255)),
 sa.Column('lastname', sa.types.String(length=255)),
 sa.Column('email1', sa.types.String(length=255)),
 sa.Column('email2', sa.types.String(length=255)),
 sa.Column('workphone', sa.types.String(length=255)),
 sa.Column('mobile', sa.types.String(length=255)),
 sa.Column('company', sa.types.String(length=255)),
 sa.Column('category', sa.types.String(length=255)),
 sa.Column('job_role', sa.types.String(length=255)),
 sa.Column('mailer', sa.types.Boolean),
 sa.Column('type', sa.types.Integer), # 0: contact, 1: press
 sa.Column('modified', sa.types.DateTime),
 )

 class ArkContact(object):
 def __init__(self):
 self.category = 0
 self.type = 0
 self.modified = datetime.datetime.now()

 *#due_contact_association
 contact_due_contact = sa.Table('contact_duedate_user_association',
 meta.metadata,
 sa.Column('contact_id', sa.types.Integer, sa.ForeignKey('contacts.id'),
 primary_key = True),
 sa.Column('user_id', sa.types.Integer, sa.ForeignKey('users.id'),
  primary_key = True),
 sa.Column('modded', sa.types.Date)
 )

 class ArkContactDueDate(object):
 def __init__(self):
 pass*


 *# ArkContactDueDate
 orm.mapper(ArkContactDueDate, contact_due_contact, properties={
 'contact': orm.relation(ArkContact, backref = 'due_dates')
 })*

 # ArkUser - users module
 orm.mapper(ArkUser, users_table, properties={
 'notes': orm.relation(ArkNote,
 secondary=user_notes_table,
 single_parent=True,
 backref='user',
 order_by=notes_table.c.date,
 cascade=all, delete, delete-orphan),
 'software': orm.relation(ArkSoftware,
 secondary=user_software_table,
 backref='users'),
 'ratings': orm.relation(ArkUserSoftwareRating,
 cascade=all, delete,
 backref='user'),
 'job': orm.relation(ArkJob,
 backref='user'),
 *'due_contacts': orm.relation(ArkContactDueDate,
  backref = 'due_user',
  single_parent=True)*
 })

 --
 You received this message because you are subscribed to the Google Groups
 sqlalchemy group.
 To post to this group, send email to sqlalchemy@googlegroups.com.
 To unsubscribe from this group, send email to
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at
 http://groups.google.com/group/sqlalchemy?hl=en.


  --
 You received this message because you are subscribed to the Google Groups
 sqlalchemy group.
 To post to this group, send email to sqlalchemy@googlegroups.com.
 To unsubscribe from this group, send email to
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at
 http://groups.google.com/group/sqlalchemy?hl=en.




-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy 

Re: [sqlalchemy] Re: Aliasing a constant within a recursive CTE

2012-07-10 Thread Michael Bayer

On Jul 10, 2012, at 2:04 AM, Russell Warren wrote:

 
 As per the comments in the code, the alias is absolutely required (it gets 
 mangled without the alias), but is seemingly pointless in the resulting SQL.  


Referring to PG's docs:

http://www.postgresql.org/docs/8.4/static/queries-with.html

when I wrote the CTE functionality, I designed it to suit the included_parts 
example, where you can see there is an alias to included_parts.This alias 
fits naturally into SQLAlchemy's system of aligning object identity with 
lexical identity, that is, to say x == 5, you need an x object that is 
unique in the query based on it's Python identity.

But you're right, I didn't study the previous example in that doc, which refers 
to t without any alias.   This usage is not nearly as natural, because t 
refers to the UNION ALL as a whole, including the two select statements, one of 
which was called t as well.  So referring to both the inner and outer t at 
the same time doesn't work with the SQLA's usual approach.

So some modifications to CTE are made in r079123b04dc6 (0.8) / ra742d1526e86 
(0.7)  such that CTEs are now rendered based on name-based logic only.  A given 
CTE name will only be rendered as a full statement once, and precedence rules 
now ensure that the outermost CTE is the one that's rendered in all cases.   
Two entirely non-related CTEs with the same name now generates a CompileError.

With this change, your original intuition:

import sqlalchemy as sa
#set up the non-recursive part of the query (sort of?)...
cte = sa.select(
   [sa.literal(0).label(x), ]
   ).cte(name = cte, recursive = True)
#bring in the recursive part (sort of?)...
cte = cte.union_all(
   sa.select([cte.c.x + 1, ]).\
   where(cte.c.x  10)
)
#select from the resulting CTE...
statement = sa.select([cte.c.x, ])
print statement

works as you expect:

WITH RECURSIVE cte(x) AS 
(SELECT :param_1 AS x UNION ALL SELECT cte.x + :x_1 AS anon_1 
FROM cte 
WHERE cte.x  :x_2)
 SELECT cte.x 
FROM cte

the original output you were getting isn't all that confusing (any more than 
the whole CTE thing is in the first place) - it just rendered cte(x) twice, one 
for each version used in the query.   

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Re: Aliasing a constant within a recursive CTE

2012-07-10 Thread Russell Warren
On Tue, Jul 10, 2012 at 11:31 AM, Michael Bayer mike...@zzzcomputing.comwrote:

 So some modifications to CTE are made in r079123b04dc6 (0.8) /
 ra742d1526e86 (0.7)  such that CTEs are now rendered based on name-based
 logic only.  A given CTE name will only be rendered as a full statement
 once, and precedence rules now ensure that the outermost CTE is the one
 that's rendered in all cases.   Two entirely non-related CTEs with the same
 name now generates a CompileError.


Awesome.  Thanks for the changes, Mike.  I confirmed it works as advertised
for 0.7.9 (but you knew that).

Until 0.7.9 is released I'll just use the cte_working alias trick.  Your
fix makes it unnecessary, but it doesn't seem to do any harm and will still
work later so I'm set.

Thanks again.  And yeah, I agree that CTE thing/syntax is more than a bit
confusing in general!  Incredibly useful, though.

Russ

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] fractional second percision- mysql

2012-07-10 Thread James



 I have not made any changes, have only proposed some hypothetical changes 
 for the 0.7 series.  I don't have this newest version of MySQL installed, 
 so I was asking you to test the workaround I gave and/or the patch, to 
 ensure it solves all the problems fully.  This testing would also establish 
 that the MySQL DBAPI is properly receiving/returning the microseconds field.

 If the workarounds I gave solve your problem fully, then I can commit the 
 patch to SQLAlchemy and resolve that we are doing all that's needed for 
 fractional time support.


I have tried implementing your suggestions. Unfortunately, your workaround 
did not solve my problem fully. I successfully created the FracTime type 
which extends Time and that shows a field for fractional seconds. However, 
when I try to insert values into the FracTime column, I am still unable to 
to specify the fractional seconds part. Even after modifying Time's process 
method in lib/sqlalchemy/dialects/mysql/base.py to accept microseconds, I 
was still unable to get it to work. 

To ensure that it was not a problem with sqlalchemy, I turned on logging to 
look at was being passed to the DBAPI. What I see is:

...
INFO:sqlalchemy.engine.base.Engine.0x...a3d0:(4L, 7.48, 0.27, 
datetime.timedelta
(0, 8, 26), 93, 0, 0, 62032, 0, 0, 19, 15573, 0) 
...

It looks like datetime.timedelta is holding the microseconds correctly 
(that is 0 minutes, 8 seconds and 26 microseconds). It looks to me that 
sqlalchemy is correctly passing the microsecond value onto the DBAPI. After 
your workaround, this seems to have confirmed that I am having a problem 
with my DBAPI's (which I think is MySQLdb) communication with the db.

Please let me know if you have anymore ideas. Thank you for your 
suggestions.

-James 

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/OLtWHwRJzKMJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] fractional second percision- mysql

2012-07-10 Thread Michael Bayer

On Jul 10, 2012, at 2:08 PM, James wrote:

 
 I have not made any changes, have only proposed some hypothetical changes for 
 the 0.7 series.  I don't have this newest version of MySQL installed, so I 
 was asking you to test the workaround I gave and/or the patch, to ensure it 
 solves all the problems fully.  This testing would also establish that the 
 MySQL DBAPI is properly receiving/returning the microseconds field.
 
 If the workarounds I gave solve your problem fully, then I can commit the 
 patch to SQLAlchemy and resolve that we are doing all that's needed for 
 fractional time support.
 
 
 I have tried implementing your suggestions. Unfortunately, your workaround 
 did not solve my problem fully. I successfully created the FracTime type 
 which extends Time and that shows a field for fractional seconds. However, 
 when I try to insert values into the FracTime column, I am still unable to to 
 specify the fractional seconds part. Even after modifying Time's process 
 method in lib/sqlalchemy/dialects/mysql/base.py to accept microseconds, I was 
 still unable to get it to work. 
 
 To ensure that it was not a problem with sqlalchemy, I turned on logging to 
 look at was being passed to the DBAPI. What I see is:
 
 ...
 INFO:sqlalchemy.engine.base.Engine.0x...a3d0:(4L, 7.48, 0.27, 
 datetime.timedelta
 (0, 8, 26), 93, 0, 0, 62032, 0, 0, 19, 15573, 0) 
 ...
 
 It looks like datetime.timedelta is holding the microseconds correctly (that 
 is 0 minutes, 8 seconds and 26 microseconds). It looks to me that sqlalchemy 
 is correctly passing the microsecond value onto the DBAPI. After your 
 workaround, this seems to have confirmed that I am having a problem with my 
 DBAPI's (which I think is MySQLdb) communication with the db.
 
 Please let me know if you have anymore ideas. Thank you for your suggestions.

Yeah, I kind of suspected MySQLdb might have problems here.  You need to file a 
bug report with the DBAPI's bug tracker:

http://sourceforge.net/tracker/?group_id=22307atid=374932

poke around there and see if someone's already requested this feature.


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.