Не удалось сделать запрос с явной последовательностью соединения (включая таблицу псевдонимов) в SQLAlchemy - PullRequest
0 голосов
/ 06 марта 2012

У меня проблемы с выполнением запроса SQLAlchemy между двумя таблицами:

ProcessedDataset
    - ID 
ProcDSParent
    - ThisDataset (foreign key to ProcessedDataset.ID)
    - ItsParent   (foreign key to ProcessedDataset.ID)

Чтобы найти Parent и Child для Dataset, мне нужно явно указать последовательность соединения между: ProcessedDataset <- <code>ProcDSParent -> ProcessedDataset

После создания для них другого псевдонима, я пробую другой подход к объединению, но все равно не могу его получить.

Демонстрация с помощью findParent из Dataset:

dataset = DB.db_tables[db_alias]['ProcessedDataset']
dsparent = DB.db_tables[db_alias]['ProcDSParent']

parent = dataset.alias('ProcessedDataset_ItsParent')
child_parent = dsparent.alias('ThisDataset_ItsParent')

keylist = [parent.c.Name]
whereclause = dataset.c.Name.op('=')('Test')

  • Подход <1>:

FromClause.join + expression.select

r_join = dataset
r_join.join(child_parent, dataset.c.ID == child_parent.c.ThisDataset)
r_join.join(parent, child_parent.c.ItsParent == parent.c.ID)

query = select(keylist, from_obj=r_join, whereclause=whereclause)

print query
SELECT `ProcessedDataset_ItsParent`.`Name`
FROM `ProcessedDataset` AS `ProcessedDataset_ItsParent`, `ProcessedDataset`
WHERE `ProcessedDataset`.`Name` = %s

  • Подход <2>:

orm.join + expression.select

join2 = join(dataset, child_parent, dataset.c.ID == child_parent.c.ThisDataset)
join2.join(dsparent, child_parent.c.ItsParent == parent.c.ID)

print query
SELECT `ProcessedDataset_ItsParent`.`Name`
FROM `ProcessedDataset` AS `ProcessedDataset_ItsParent`,
     `ProcessedDataset` INNER JOIN `ProcDSParent` AS `ThisDataset_ItsParent` ON
     `ProcessedDataset`.`ID` = `ThisDataset_ItsParent`.`ThisDataset`
WHERE `ProcessedDataset`.`Name` = %s

Как видите, ни один изэто Parent из Dataset, что должно быть:

SELECT `ProcessedDataset_ItsParent`.`Name`
FROM `ProcessedDataset` 
   INNER JOIN `ProcDSParent` AS `ThisDataset_ItsParent` ON  
          `ProcessedDataset`.`ID` = `ThisDataset_ItsParent`.`ThisDataset`
   INNER JOIN `ProcessedDataset` AS `ProcessedDataset_ItsParent` ON
          `ThisDataset_ItsParent`.'ItsParent` = `ProcessedDataset_ItsParent`.`ID`
WHERE `ProcessedDataset`.`Name` = %s

Цените любую помощь, застрявшую здесь уже пару дней!

Донг

Прикрепление минимального кода DDL и кода Python

CREATE TABLE ProcessedDataset
  (
    ID                    BIGINT UNSIGNED not null auto_increment,
    Name                  varchar(500)      not null,

    primary key(ID)
  ) ;


CREATE TABLE ProcDSParent
  (
    ID                    BIGINT UNSIGNED not null auto_increment,
    ThisDataset           BIGINT UNSIGNED   not null,
    ItsParent             BIGINT UNSIGNED   not null,

    primary key(ID),
    unique(ThisDataset,ItsParent)
  ) ;

ALTER TABLE ProcDSParent ADD CONSTRAINT 
    ProcDSParent_ThisDataset_FK foreign key(ThisDataset) references ProcessedDataset(ID) on delete CASCADE
;
ALTER TABLE ProcDSParent ADD CONSTRAINT 
    ProcDSParent_ItsParent_FK foreign key(ItsParent) references ProcessedDataset(ID) on delete CASCADE
;

INSERT INTO ProcessedDataset VALUES (0, "ds0");
INSERT INTO ProcessedDataset VALUES (1, "ds1");
INSERT INTO ProcessedDataset VALUES (2, "ds2");
INSERT INTO ProcessedDataset VALUES (3, "ds3");
INSERT INTO ProcessedDataset VALUES (4, "ds4");
INSERT INTO ProcessedDataset VALUES (5, "ds5");
INSERT INTO ProcessedDataset VALUES (6, "ds6");
INSERT INTO ProcessedDataset VALUES (7, "ds7");

INSERT INTO ProcDSParent VALUES (0, 0, 1);
INSERT INTO ProcDSParent VALUES (1, 2, 1);
INSERT INTO ProcDSParent VALUES (2, 1, 3);
INSERT INTO ProcDSParent VALUES (3, 3, 4);
INSERT INTO ProcDSParent VALUES (4, 5, 6);
INSERT INTO ProcDSParent VALUES (5, 7, 6);

(ds0, ds2) -> ds1 -> ds3 -> ds4

(ds5, ds7) -> ds6

from sqlalchemy import Table, create_engine, MetaData
from sqlalchemy import and_
from sqlalchemy.sql import select
from sqlalchemy.orm import join


url = 'mysql://cms:passcms@localhost:3306/testbed'
engine = create_engine(url, strategy = 'threadlocal')
kwargs = {'autoload':True}
db_meta = MetaData()
db_meta.bind = engine

dataset = Table('ProcessedDataset', db_meta, **kwargs)
dsparent = Table('ProcDSParent', db_meta, **kwargs)

parent = dataset.alias('ProcessedDataset_ItsParent')
child_parent = dsparent.alias('ThisDataset_ItsParent')

keylist = [parent.c.Name]
whereclause = dataset.c.Name.op('=')('ds0')

r_join = dataset
r_join.join(child_parent, dataset.c.ID == child_parent.c.ThisDataset)
r_join.join(parent, child_parent.c.ItsParent == parent.c.ID)

query = select(keylist, whereclause)
print query
print engine.execute(query).fetchall()

query.append_from(r_join)
print query
print engine.execute(query).fetchall()

query = select(keylist, from_obj=r_join, whereclause=whereclause)
print query
print engine.execute(query).fetchall()

join2 = join(dataset, child_parent, dataset.c.ID == child_parent.c.ThisDataset)
join2.join(dsparent, child_parent.c.ItsParent == parent.c.ID)


query.append_from(join2)
print query
print engine.execute(query).fetchall()

query = select(keylist, from_obj=join2, whereclause=whereclause)
print query
print engine.execute(query).fetchall()

1 Ответ

0 голосов
/ 07 марта 2012

Майкл Байер ответил мне по почте.

метод join() возвращает новый объект Join, который представляет соединение. Оригинальный объект неизменен:

r_join = dataset
r_join = r_join.join(child_parent, ...)
r_join = r_join.join(parent, ...)

И еще я попробовал orm.join:

join1 = join(child_parent, dataset, child_parent.c.ThisDataset == dataset.c.ID)
join2 = parent.join(join1, parent.c.ID == child_parent.c.ItsParent)
...