2010-06-17 4 views
4

나는 내 데이터베이스 쿼리 최적화하고 싶었 :SQLAlchemy의 : 이상 선택 여러 테이블

link_list = select(
    columns=[link_table.c.rating, link_table.c.url, link_table.c.donations_in], 
    whereclause=and_(
     not_(link_table.c.id.in_(
      select(
       columns=[request_table.c.recipient], 
       whereclause=request_table.c.donator==donator.id 
      ).as_scalar() 
     )), 
     link_table.c.id!=donator.id, 
    ), 
    limit=20, 
).execute().fetchall() 

을 하나 개의 쿼리에서 두 선택을 병합하려고 :

link_list = select(
    columns=[link_table.c.rating, link_table.c.url, link_table.c.donations_in], 
    whereclause=and_(
     link_table.c.active==True, 
     link_table.c.id!=donator.id, 
     request_table.c.donator==donator.id, 
     link_table.c.id!=request_table.c.recipient, 
    ), 
    limit=20, 
    order_by=[link_table.c.rating.desc()] 
).execute().fetchall() 

데이터베이스 스키마는 다음과 같습니다

link_table = Table('links', metadata, 
    Column('id', Integer, primary_key=True, autoincrement=True), 
    Column('url', Unicode(250), index=True, unique=True), 
    Column('registration_date', DateTime), 
    Column('donations_in', Integer), 
    Column('active', Boolean), 
) 
request_table = Table('requests', metadata, 
    Column('id', Integer, primary_key=True, autoincrement=True), 
    Column('recipient', Integer, ForeignKey('links.id')), 
    Column('donator', Integer, ForeignKey('links.id')), 
    Column('date', DateTime), 
) 

link_table의 한 링크를 가리키는 request_table에 여러 링크 (기부자)가 있습니다. link_table에서 아직 "요청하지 않은"링크를 원합니다.

하지만 작동하지 않습니다. 내가 실제로하려는 일이 실제로 가능합니까? 그렇다면 어떻게해야할까요?

미리 감사드립니다.

+1

나는이 문제를 직접 해결했다. 왼쪽 대외 조인이 필요했는데, 이는 다 대일 관계이기 때문입니다. 감사합니다. –

+8

@ahojnnes : 역사적인 목적으로 답을 해결책에 게시하십시오. – nosklo

+0

솔직히 말하면 내 솔루션은 아무런 해결책도 아니 었습니다. 왜냐하면 결국 나는 뭔가 다른 것을 실현했기 때문입니다. 그러나 지금은 조인으로는 불가능하다고 생각하는 지점에 도달했습니다. 적어도 두 가지 선택과 마찬가지로 효율적이지는 않습니다. 그래서 나는 여전히 대답에 대해 기뻐할 것입니다! –

답변

0

masida's answer에 Riffing :

첫째, 원래 쿼리 :

>>> print select(
...  columns=[link_table.c.url, link_table.c.donations_in], 
...  whereclause=and_(
...   not_(link_table.c.id.in_(
...    select(
...     columns=[request_table.c.recipient], 
...     whereclause=request_table.c.donator==5 
...   ).as_scalar() 
...  )), 
...   link_table.c.id!=5, 
... ), 
...  limit=20, 
...) 
SELECT links.url, links.donations_in 
FROM links 
WHERE links.id NOT IN (SELECT requests.recipient 
FROM requests 
WHERE requests.donator = :donator_1) AND links.id != :id_1 
LIMIT 20 

그리고 존재의 관점에서 재 작성() :

>>> print select(
...  columns=[link_table.c.url, link_table.c.donations_in], 
...  whereclause=and_(
...  not_(exists().where(request_table.c.donator==5)), 
...  # ^^^^^^^^^^^^^^ 
...   link_table.c.id!=5, 
... ), 
...  limit=20, 
...) 
SELECT links.url, links.donations_in 
FROM links 
WHERE NOT (EXISTS (SELECT * 
FROM requests 
WHERE requests.donator = :donator_1)) AND links.id != :id_1 
LIMIT 20 
+1

이 종류의 재 작성은 부적절하게 최적화 된 하위 선택으로 악명 높은 MySQL에서 의미가 있습니다. 다른 DBMS는 전혀 도움이되지 않을 수 있습니다. 예를 들어 postgresql은 anti-join으로 "subselect에없는"것을 계획 할 것입니다. "존재하지 않는다"는 것과 정확히 같은 방식입니다. – SingleNegationElimination