[sqlalchemy] Re: ORM Many to Many Across Two Databases

2009-10-15 Thread Luke Arno
My apologies. I must have misunderstanding the behavior of
the schema option and thus its intent. How do I configure a
relation across two logical databases using schema?

I have tried the following:

engine = create_engine(DATABASEURI, echo=True)
meta = MetaData()
meta.bind = engine

left_schema = "LeftDatabaseName"
right_schema = "RightDatabaseName"

left_table = Table('LeftTable', meta,
Column('id', Integer, primary_key=True),
Column('description', String(128)),
schema=left_schema)

right_table = Table('RightTable', meta,
Column('id', Integer, primary_key=True),
Column('description', String(128)),
schema=right_schema)

assoc_table = Table('LeftAssoc', meta,
Column('left_id', Integer),
Column('right_id', Integer),
#quote_schema=False,
schema=left_schema)

MySession = sessionmaker(bind=engine)

class MyBase(object):
def __init__(self, description):
self.description = description
def __str__(self):
return str(self.description)

class Left(MyBase): pass

class Right(MyBase): pass

mapper(Left, left_table)
mapper(Right, right_table, properties={
'lefts': relation(Left, secondary=assoc_table,
primaryjoin=(right_table.c.id==assoc_table.c.right_id),
secondaryjoin=(assoc_table.c.left_id==left_table.c.id),
foreign_keys=[assoc_table.c.left_id, assoc_table.c.right_id],
backref="rights"),
})

if __name__ == '__main__':
meta.drop_all()
meta.create_all()
session = MySession()
left1 = Left('Left 1')
left2 = Left('Left 2')
right1 = Right('Right 1')
right2 = Right('Right 2')
left1.rights.extend([right1, right2])
right1.lefts.extend([left1, left2])
session.add_all([left1, left2, right1, right2])
session.commit()

left1 = session.query(Left).filter_by(description="Left 1").one()
print left1
for right in left1.rights:
print " "*4, right
for left in right.lefts:
print " "*8, left

The table name in the generated SQL is DBNAME.TABLENAME,
which doesn't work. It needs to be

DBNAME.SCHEMANAME.TABLENAME
or
DBNAME..TABLENAME (uses default schema)

I tried using quote_schema=False and adding a "." to the end
of the schema value (schema="DBNAME.") but this results in
the broken SQL mentioned earlier:

SELECT [LeftTable_1].description AS [DBNAME._LeftTab_1]

Using schema="DBNAME.SCHEMANAME" didn't work either.

Please let me know how to do this correctly.

I am using:

SQL Server 8.0
Hardy Heron
Python 2.5
SQLAlchemy 0.5.6
pymssql 1.0.2

Thanks, again!

- Luke

On Wed, Oct 14, 2009 at 6:46 PM, Michael Bayer wrote:

>
> Luke Arno wrote:
> > So, is there any chance that relations across multiple _logical_
> > databases on a _single_ physical server will be supported by
> > SQLAlchemy in the future?
>
> that is supported now, via the "schema" argument to Table, assuming you
> are connecting with an account that has access to all logical databases.
>
> relation() supports spanning physical databases as well, if you either
> ensure the "secondary" table is on the same server as the target, or
> alternatively map the association table explicitly as I said in my initial
> response.
>
>
>
>
>
>
> >
> > Thanks.
> >
> > - Luke
> >
> > On Wed, Oct 14, 2009 at 3:01 PM, Luke Arno  wrote:
> >
> >> Thanks, Simon. Good suggestion, but these are databases and not
> >> schema within a database. If I use the schema="MyDatabase." (
> >> notice the ".") and quote_schema=False, the table names come out
> >> like I want, but look at what happens to the label here:
> >>
> >> SELECT [LeftTable_1].description AS [MyDatabase._LeftTab_1]
> >> FROM MyDatabase..[LeftTable] AS [LeftTable_1]
> >> WHERE [LeftTable_1].id = %(param_1)s
> >>
> >> That is really abusing the schema feature, so this is not a bug... I
> >> just wish there were a databasename="Foo" option for Table() so I
> >> could use these ugly databases the way they are. :(
> >>
> >>
> >> On Wed, Oct 14, 2009 at 11:51 AM, King Simon-NFHD78 <
> >> simon.k...@motorola.com> wrote:
> >>
> >>>
> >>> > -Original Message-
> >>> > From: sqlalchemy@googlegroups.com
> >>> > [mailto:sqlalch...@googlegroups.com] On Behalf Of Luke Arno
> >>> > Sent: 14 October 2009 16:41
> >>> > To: sqlalchemy@googlegroups.com
> >>> > Subject: [sqlalchemy] Re: ORM 

[sqlalchemy] Re: ORM Many to Many Across Two Databases

2009-10-14 Thread Luke Arno
So, is there any chance that relations across multiple _logical_
databases on a _single_ physical server will be supported by
SQLAlchemy in the future?

As I mentioned before, this could work (at least for MSSQL)
if we only had a databasename="foo" on Table(). I am not
really sure how much work it would be, but it _sounds_ easy. :)

Thanks.

- Luke

On Wed, Oct 14, 2009 at 3:01 PM, Luke Arno  wrote:

> Thanks, Simon. Good suggestion, but these are databases and not
> schema within a database. If I use the schema="MyDatabase." (
> notice the ".") and quote_schema=False, the table names come out
> like I want, but look at what happens to the label here:
>
> SELECT [LeftTable_1].description AS [MyDatabase._LeftTab_1]
> FROM MyDatabase..[LeftTable] AS [LeftTable_1]
> WHERE [LeftTable_1].id = %(param_1)s
>
> That is really abusing the schema feature, so this is not a bug... I
> just wish there were a databasename="Foo" option for Table() so I
> could use these ugly databases the way they are. :(
>
>
> On Wed, Oct 14, 2009 at 11:51 AM, King Simon-NFHD78 <
> simon.k...@motorola.com> wrote:
>
>>
>> > -Original Message-
>> > From: sqlalchemy@googlegroups.com
>> > [mailto:sqlalch...@googlegroups.com] On Behalf Of Luke Arno
>> > Sent: 14 October 2009 16:41
>> > To: sqlalchemy@googlegroups.com
>> > Subject: [sqlalchemy] Re: ORM Many to Many Across Two Databases
>> >
>> > It looks like if I put the relation on the obj mapped to the DB where
>> > the association table is _not_, it works in one direction.
>> > (So, in the
>> > example Right.lefts can work but Left.rights cannot.) When trying to
>> > use Left.rights, it looks for the table in the wrong database.
>> >
>> > It appears that it would be fine if I could just get the
>> > table names all
>> > qualified with database name in the issued SQL. Is there a way to
>> > make that happen, by any chance?
>> >
>>
>> You can do this by using a single engine and metadata, and passing a
>> 'schema' parameter when defining your tables:
>>
>> http://www.sqlalchemy.org/docs/05/metadata.html#specifying-the-schema-na
>> me
>>
>> Hope that helps,
>>
>> Simon
>>
>> >>
>>
>

--~--~-~--~~~---~--~~
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] Re: ORM Many to Many Across Two Databases

2009-10-14 Thread Luke Arno
Thanks, Simon. Good suggestion, but these are databases and not
schema within a database. If I use the schema="MyDatabase." (
notice the ".") and quote_schema=False, the table names come out
like I want, but look at what happens to the label here:

SELECT [LeftTable_1].description AS [MyDatabase._LeftTab_1]
FROM MyDatabase..[LeftTable] AS [LeftTable_1]
WHERE [LeftTable_1].id = %(param_1)s

That is really abusing the schema feature, so this is not a bug... I
just wish there were a databasename="Foo" option for Table() so I
could use these ugly databases the way they are. :(

On Wed, Oct 14, 2009 at 11:51 AM, King Simon-NFHD78  wrote:

>
> > -Original Message-
> > From: sqlalchemy@googlegroups.com
> > [mailto:sqlalch...@googlegroups.com] On Behalf Of Luke Arno
> > Sent: 14 October 2009 16:41
> > To: sqlalchemy@googlegroups.com
> > Subject: [sqlalchemy] Re: ORM Many to Many Across Two Databases
> >
> > It looks like if I put the relation on the obj mapped to the DB where
> > the association table is _not_, it works in one direction.
> > (So, in the
> > example Right.lefts can work but Left.rights cannot.) When trying to
> > use Left.rights, it looks for the table in the wrong database.
> >
> > It appears that it would be fine if I could just get the
> > table names all
> > qualified with database name in the issued SQL. Is there a way to
> > make that happen, by any chance?
> >
>
> You can do this by using a single engine and metadata, and passing a
> 'schema' parameter when defining your tables:
>
> http://www.sqlalchemy.org/docs/05/metadata.html#specifying-the-schema-na
> me
>
> Hope that helps,
>
> Simon
>
> >
>

--~--~-~--~~~---~--~~
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] Re: ORM Many to Many Across Two Databases

2009-10-14 Thread Luke Arno
It looks like if I put the relation on the obj mapped to the DB where
the association table is _not_, it works in one direction. (So, in the
example Right.lefts can work but Left.rights cannot.) When trying to
use Left.rights, it looks for the table in the wrong database.

It appears that it would be fine if I could just get the table names all
qualified with database name in the issued SQL. Is there a way to
make that happen, by any chance?

mapper(Left, left_table)
mapper(Right, right_table, properties={
'lefts': relation(Left, secondary=assoc_table,
primaryjoin=(right_table.c.id==assoc_table.c.right_id),
secondaryjoin=(assoc_table.c.left_id==left_table.c.id),
foreign_keys=[assoc_table.c.left_id, assoc_table.c.right_id],
backref="rights"),
})

Accessing Left.rights gives me this:

Invalid object name 'LeftAssoc'.
DB-Lib error message 20018, severity 5:
General SQL Server error: Check messages from the SQL Server.
 'SELECT [RightTable].id AS [RightTable_id], [RightTable].description AS
[RightTable_description] \nFROM [RightTable], [LeftAssoc] \nWHERE
[LeftAssoc].left_id = %(param_1)s AND [RightTable].id =
[LeftAssoc].right_id' {'param_1': 9}

I realize that this is not good DB design - not _my_ design ;) - but
I would guess it is not that rare an abuse of SQL Server. If it is not
supported now, is it worth adding such? I _sounds_ like it would be
simple to qualify the table names...

BTW, sorry for not putting [sqlalchemy] in my subject line. Thanks!

- Luke

On Wed, Oct 14, 2009 at 10:01 AM, Michael Bayer wrote:

>
> Luke Arno wrote:
> > I have a MSSQL server with two logical databases. (I inherited this
> > situation,
> > of course.) There is a table in each database and an association table in
> > one of them. What is the right way to configure this? Here is what I have
> > and
> > it complains about the values in foreign_keys. I've tried a lot of
> > permutations
> > and can't seem to hit on the right one. Thanks much!
> >
> > left_engine = create_engine(SERVER_A_DB_ONE)
> > left_meta = MetaData()
> > left_meta.bind = left_engine
> >
> > right_engine = create_engine(SERVER_A_DB_TWO)
> > right_meta = MetaData()
> > right_meta.bind = right_engine
> >
> > left_table = Table('LeftTable', left_meta,
> > Column('id', Integer, primary_key=True),
> > Column('description', String(128)))
> >
> > right_table = Table('RightTable', right_meta,
> > Column('id', Integer, primary_key=True),
> > Column('description', String(128)))
> >
> > assoc_table = Table('LeftAssoc', left_meta,
> > Column('left_id', Integer),
> > Column('right_id', Integer))
> >
> > MySession = sessionmaker(binds={
> > left_table: left_engine,
> > right_table: right_engine,
> > assoc_table: left_engine
> > })
> >
> > class Left(object): pass
> >
> > class Right(object): pass
> >
> > mapper(Left, left_table)
> >
> > mapper(Right, right_table, properties={
> > 'lefts': relation(Left, secondary=assoc_table,
> > primaryjoin=right_table.c.id==assoc_table.c.right_id,
> > secondaryjoin=assoc_table.c.left_id==left_table.c.id,
> > foreign_keys=[right_table.c.id, left_table.c.id],
> > backref="rights"),
> > })
> >
>
> the foreign keys here would be assoc_table.c.left_id and
> assoc_table.c.right_id.
>
> However I don't think relation() + secondary is going to work here.  The
> load of "child" objects will be against the target database only - there's
> no behavior such that it will separately select rows from the association
> table first, then the target table.
>
> Your two options here are to map assoc_table explicitly, optionally using
> association_proxy to have its usage be implicit, or alternately to build a
> read-only accessor on your class which manually queries the association
> table and then queries the target table.
>
> Another possibility, if this were Oracle I'd suggest using "dblink" tables
> - tables which are present in the local database but are "remote" to
> another server.   Since MS-SQL competes fiercely with Oracle I wouldn't be
> surprised if MS-SQL supports such a concept as well.
>
>
>
>
> > - Luke
> >
> > >
> >
>
>
> >
>

--~--~-~--~~~---~--~~
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] ORM Many to Many Across Two Databases

2009-10-13 Thread Luke Arno
I have a MSSQL server with two logical databases. (I inherited this
situation,
of course.) There is a table in each database and an association table in
one of them. What is the right way to configure this? Here is what I have
and
it complains about the values in foreign_keys. I've tried a lot of
permutations
and can't seem to hit on the right one. Thanks much!

left_engine = create_engine(SERVER_A_DB_ONE)
left_meta = MetaData()
left_meta.bind = left_engine

right_engine = create_engine(SERVER_A_DB_TWO)
right_meta = MetaData()
right_meta.bind = right_engine

left_table = Table('LeftTable', left_meta,
Column('id', Integer, primary_key=True),
Column('description', String(128)))

right_table = Table('RightTable', right_meta,
Column('id', Integer, primary_key=True),
Column('description', String(128)))

assoc_table = Table('LeftAssoc', left_meta,
Column('left_id', Integer),
Column('right_id', Integer))

MySession = sessionmaker(binds={
left_table: left_engine,
right_table: right_engine,
assoc_table: left_engine
})

class Left(object): pass

class Right(object): pass

mapper(Left, left_table)

mapper(Right, right_table, properties={
'lefts': relation(Left, secondary=assoc_table,
primaryjoin=right_table.c.id==assoc_table.c.right_id,
secondaryjoin=assoc_table.c.left_id==left_table.c.id,
foreign_keys=[right_table.c.id, left_table.c.id],
backref="rights"),
})

- Luke

--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---