Join table on itself to find user with same relationship

Viewed 493

EDIT: Last Chance for me, shorter question

I would like to do this query with sqlalchemy:

SELECT          first.* , 
                second.* , 
                third.* , 
                fourth.* , 
                mytable.* , 
                mytablesamerelationexist.* 
FROM            third 
LEFT OUTER JOIN mytable 
ON              third.id = mytable.id_third 
LEFT OUTER JOIN first 
ON              first.id = mytable.id_first 
LEFT OUTER JOIN second 
ON              second.id = mytable.id_second 
LEFT OUTER JOIN fourth 
ON              fourth.id = mytable.id_fourth 
LEFT OUTER JOIN mytable AS mytablesamerelationexist 
ON              mytable.id_second = mytablesamerelationexist.id_second 
AND             ( 
                                mytable.id_first = mytablesamerelationexist.id_first 
                OR              ( 
                                                mytable.id_first IS NULL 
                                AND             mytablesamerelationexist.id_first IS NULL ) 
                AND             mytable.id_third = {MYUSERPARAM} )

I would like to use contains_eager to access object something like:

third.Mytable.MyTableSameRelationExist

The rest of the query already works, I just need to do the self join.

mytable.id_first can be NULL

There is the minimum of my model definition model definition

Long Question:

What is the best way to join table on itself. My table contains 4 foreign keys and I need to use two of them to find same relationship. One of those foreign keys can be null. I need to get relation NULL == NULL. I don't want to define a foreign key on itself in the table.

I try to define my query with something like that:

tablealias = aliased(MyTable)
...
outerjoin(tablealias , and_(or_(MyTable.id_first == tablealias.first,
                                and_(MyTable.id_first.is_(None),
                                     tablealias.id_first.is_(None))),
                                MyTable.id_second == tablealias.id_second,
                            tablealias.id_third == MYUSERID)).

I would like to access result of the relationship in hierarchical way, something like MyTable.self_child.

So I add In my query:

options(contains_eager(MyTable.self_parent, MyTable.self_child))

I've try a lot of things in my MyTable class to make the relationship 'self_child' works without adding a foreign key on itself.

For now I have define id_second as foreign key because id_first can be null and I think that can be a problem (Am I right?):

self_parent = relationship("MyTable",  primaryjoin='foreign(mytable.id_second) == remote(foreign(mytable.id_second))')
self_child = relationship("MyTable", primaryjoin='foreign(mytable.id_second) == remote(mytable.id_second)')

With this definition, when I initialize my database, I got error:

'Table' object has no attribute 'id_second'

Do I necessary need to add a relationship in my Class if no foreign key comes from itself? If not necessary, how can I access the relation define with contains_eager? How to define it correctly?

EDIT: I pass the error below but I got a lot of different error, something like

ambiguous column name

or

they are the same entity

For le last error I define my code in Class like:

self_child = relationship("MyTable", primaryjoin=and_(or_(foreign(id_first) == id_first, and_(foreign(id_first).is_(None), id_first.is_(None))).self_group(), foreign(id_second) == id_second).self_group(), remote_side=[id_second, id_first], lazy='joined')

The query:

tablealias = aliased(MyTable)
...
outerjoin(crotalias.self_child)
...
options(contains_eager(FirstLevel.mytable, crotalias.self_child))

If I use backref="self_parent"

I got message:

MyTable.self_child and back-reference MyTable.self_parent are both of the same direction symbol('ONETOMANY'). Did you mean to set remote_side on the many-to-one side ?

Edit: There is the minimum of my model definition model definition

Any hint will be appreciated.

1 Answers

I'm surprise then I haven't received a hint for this question.

For now I used a second idea, I add the list of id_first and id_second in the user's session. So, I'm able to loop through the result of my query to match with the value of my user.

Related