jonathan ellis pointed us all to a great series of articles
concerning primary keys:
http://spyced.blogspot.com/2006/07/single-column-primary-keys-should-
be.html
the gist of the articles is that *any* concept you are trying to
store in a database usually has some kind of unique identifying key.
in your case, the combination of "uid" and "timestamp" is the primary
key. SQLAlchemy is fine with this. even if you dont have these
columns explicitly defined as part of a primary key in your table
schema (which you probably should), you can still tell a mapper what
columns compose the primary key like this:
mapper(someclass, sometable, primary_key=[sometable.c.uid,
sometable.c.timestamp])
now for the next thing. SA, like every ORM I have ever seen, maps
object instances on a one-to-one basis against this primary key
identity, and in memory stores the instances in a map called an
"identity map". Which means, if you have an object instance A with
primary key "3", and then you change its primary key to "4", then
object instance A is essentially a different instance; the old number
"3" still remains. If you did that, SA would get pretty confused
and function in an undefined manner; since it still has that instance
mapped to the identity of "3". So the best you can do, assuming you
want the mappers to save these instances, is to have a distinct
object instance represented for each unique primary key value. If you
want a single object to change its "identity" under the scenes in a
transparent manner, you can construct a proxying object that talks to
the underlying mapped object, or use a similar architectural pattern.
Alternatively, you can simply map to the exact select statement you
have below, using the aggregate MAX function, etc. That way you
would just have a single object instance that corresponds to the
tabular product of that exact statement. However, while this mapper
will be able to query instances, it will not have all the information
it needs to save changes to those instances (or new instances) to the
database.
you could also do a combination of both approaches; SQLAlchemy
supports a few patterns to allow multiple mappers to exist for a
single class (or you could use multiple classes).
In either approach, you also have a lot of ways you could drop down
to raw SQL if needed.
so the gist is, SA is probably open ended enough to allow your
patterns to be successfully used; however its going to require some
creativity and slightly more in-depth knowledge about the session's
behavior since the ORM is designed around an immutable primary key
assumption.
On Aug 4, 2006, at 10:57 AM, Bill Noon wrote:
> I am at a loss on how to use sqlAlchemy Data Mappers to map a set of
> sql tables that don't have a unique primary key.
>
> Lets say I have these tables:
> CREATE TABLE Customer (
> uid integer,
> timestamp numeric,
> ts_flag text,
> name text,
> mail_addr integer,
> bill_addr integer
> );
> CREATE TABLE Address (
> uid integer,
> timestamp numeric,
> ts_flag text,
> person_uid integer,
> addr text
> );
> CREATE TABLE Order (
> uid integer,
> timestamp numeric,
> ts_flag text,
> person_uid integer,
> );
>
> Each time the data is updated, the timestamp is updated. The ts_flag
> indicates 'latest','historical', or 'deleted' and is used to sync to
> other databases.
>
> The combination of uid and timestamp _is_ unique but one customer
> would
> have a series of changes. The desired record depends on the use,
> either latest timestamp (not deleted), latest timestamp before a date,
> etc.
>
> Looking through the mail archives, there were several suggestions to
> split the current data from historical changes, but that complicates a
> standard query where you need the info current at a particular time
> (i.e. when an order was filled).
>
> To select the right set of records for an order, SA would need to
> generate a select clause similar to the following:
> select distinct Customer.uid, max(Customer.timestamp), mail_addr,
> bill_addr
> from Order, Customer
> where Order.uid = ? and Customer.uid = Order.person_uid and
> Customer.timestamp <= Order.timestamp;
>
> Subselects for the mailing and billing addresses would be similar.
>
> To get the most current records for a customer, the timestamp would be
> just the most recent. There would be other constraints for non-
> deleted
> customers.
>
> Is there a way to define a Mapper to handle these cases?
>
> Thanks --Bill
>
>
>
>
> ----------------------------------------------------------------------
> ---
> Take Surveys. Earn Cash. Influence the Future of IT
> Join SourceForge.net's Techsay panel and you'll get the chance to
> share your
> opinions on IT & business topics through brief surveys -- and earn
> cash
> http://www.techsay.com/default.php?
> page=join.php&p=sourceforge&CID=DEVDEV
> _______________________________________________
> Sqlalchemy-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Sqlalchemy-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users