Как выбрать данные из нескольких кастомных таблиц?
        Мне нужно выбрать данные из нескольких кастомных таблиц через pdoResources, но не получается настроить Join-ы правильно.
Есть несколько кастомных таблиц с одинаковой структурой полей и с сгенерированными моделями.
Данные из одной таблицы выводятся легко:
Пытаюсь делать как-то так:
&showLog:
Пробовал то же с &leftJoin и &rightJoin, но результат тот же самый.
В результате должны выбраться из всех подключаемых таблиц все строки где поле publishedby равно 2. Всё это дело нужно отсортировать по полю publishedon (timestamp-поле) в обратном порядке DESC.
Что я неправильно делаю?
    
    
                                                                                
            Есть несколько кастомных таблиц с одинаковой структурой полей и с сгенерированными моделями.
Данные из одной таблицы выводятся легко:
[[!pdoResources?
    &loadModels=`orders_external`
    &class=`BazOrders1External`
    &tpl=`tpl.orders.row`
    &limit=`0`
    &where=`{ 'publishedby':2 }`
]]А вот как приджойнить сюда другие таблицы по тому же условию?Пытаюсь делать как-то так:
[[!pdoResources?
    &loadModels=`orders_external,orders_internal,orders_rails`
    &class=`BazOrders1External`
    &innerJoin=`{ 
                    "BazOrders2Internal":{ "alias":"Internal","on":"Internal.publishedby = \"2\"" },
                    "BazOrders4Rails":{ "alias":"Rails","on":"Rails.publishedby = \"2\"" }
                     }`
    &tpl=`tpl.orders.row`
    &limit=`0`
    &where=`{ 'publishedby':2 }`
    &showLog=`1`
]]Но выводит только одну строку из первой таблицы orders_external (BazOrders1External), а не из джойнов.&showLog:
0.0000880: Loaded model "orders_external" from "/core/components/orders_external/model/"
0.0000651: Loaded model "orders_rails" from "/core/components/orders_rails/model/"
0.0003929: pdoTools loaded
0.0000181: xPDO query object created
0.0001719: innerJoined BazOrders2Internal as Internal
0.0004570: innerJoined BazOrders4Rails as Rails
0.0003359: Added selection of BazOrders1External: SQL_CALC_FOUND_ROWS `id`, `parent`, `publishedon`, `editedon`, `published`, `publishedby`, `editedby`, `pagetitle`, `description`, `alias`, `export_country`, `export_city`, `export_city_port`, `import_country`, `import_city`, `import_city_port`, `phone`, `phone1`, `phone2`, `phone3`, `email`, `skype`, `icq`, `face`, `company`, `date_from`, `date_to`, `model`, `model_number`, `car_number`, `cargo_number`, `transport_type_number`, `passenger_number`, `source`, `cargo_type`, `cargo_type_add`, `cargo_type_internal`, `cargo_type_passengers`, `cargo_type_post`, `container_type_rails`, `container_type_seafreight`, `transport_type`, `transport_type_passengers`, `transport_type_post`, `cargo_volume`, `cargo_volume_passengers`, `cargo_volume_post`, `payment`, `documents`, `supplementary`, `images`
0.0001118: Added where condition: publishedby=2
0.0000200: Sorted by BazOrders1External.publishedon, DESC
0.0001690: SQL prepared "SELECT SQL_CALC_FOUND_ROWS `BazOrders1External`.`id`, `BazOrders1External`.`parent`, `BazOrders1External`.`publishedon`, `BazOrders1External`.`editedon`, `BazOrders1External`.`published`, `BazOrders1External`.`publishedby`, `BazOrders1External`.`editedby`, `BazOrders1External`.`pagetitle`, `BazOrders1External`.`description`, `BazOrders1External`.`alias`, `BazOrders1External`.`export_country`, `BazOrders1External`.`export_city`, `BazOrders1External`.`export_city_port`, `BazOrders1External`.`import_country`, `BazOrders1External`.`import_city`, `BazOrders1External`.`import_city_port`, `BazOrders1External`.`phone`, `BazOrders1External`.`phone1`, `BazOrders1External`.`phone2`, `BazOrders1External`.`phone3`, `BazOrders1External`.`email`, `BazOrders1External`.`skype`, `BazOrders1External`.`icq`, `BazOrders1External`.`face`, `BazOrders1External`.`company`, `BazOrders1External`.`date_from`, `BazOrders1External`.`date_to`, `BazOrders1External`.`model`, `BazOrders1External`.`model_number`, `BazOrders1External`.`car_number`, `BazOrders1External`.`cargo_number`, `BazOrders1External`.`transport_type_number`, `BazOrders1External`.`passenger_number`, `BazOrders1External`.`source`, `BazOrders1External`.`cargo_type`, `BazOrders1External`.`cargo_type_add`, `BazOrders1External`.`cargo_type_internal`, `BazOrders1External`.`cargo_type_passengers`, `BazOrders1External`.`cargo_type_post`, `BazOrders1External`.`container_type_rails`, `BazOrders1External`.`container_type_seafreight`, `BazOrders1External`.`transport_type`, `BazOrders1External`.`transport_type_passengers`, `BazOrders1External`.`transport_type_post`, `BazOrders1External`.`cargo_volume`, `BazOrders1External`.`cargo_volume_passengers`, `BazOrders1External`.`cargo_volume_post`, `BazOrders1External`.`payment`, `BazOrders1External`.`documents`, `BazOrders1External`.`supplementary`, `BazOrders1External`.`images` FROM `modx_baz_orders_1_external` AS `BazOrders1External` JOIN `modx_baz_orders_4_rails` `Rails` ON Rails.publishedby = "2" WHERE `BazOrders1External`.`publishedby` = 2 ORDER BY BazOrders1External.publishedon DESC "
0.0423579: SQL executed
0.0001020: Total rows: 1
0.0000191: Rows fetched
0.0013330: Loaded chunk "tpl.orders.row.my"
0.0137930: Compiled Fenom chunk with name "chunk/970"
0.0589390: Returning processed chunks
0.1034300: Total time
23 855 104: Memory usageПробовал то же с &leftJoin и &rightJoin, но результат тот же самый.
В результате должны выбраться из всех подключаемых таблиц все строки где поле publishedby равно 2. Всё это дело нужно отсортировать по полю publishedon (timestamp-поле) в обратном порядке DESC.
Что я неправильно делаю?
Комментарии: 17
                Что-то мне подсказывает, что тебе нужно воспользоваться UNION, а не JOIN.            
                    
                Точно, очень даже логично… 
Только вот как использовать UNION в pdoResources?..
Или прийдется писать свой сниппет для вывода?
                    Только вот как использовать UNION в pdoResources?..
Или прийдется писать свой сниппет для вывода?
&innerJoin=`{ 
	"BazOrders2Internal":{ "alias":"Internal","on":"Internal.publishedby = \"2\"" },
	"BazOrders4Rails":{ "alias":"Rails","on":"Rails.publishedby = \"2\"" }
}`И к чему здесь таблицы присоединяются? К цифре 2?Всё же расписано, почему не прочитать? docs.modx.pro/components/pdotools/classes/pdofetch#Метод-addJoins
                Вроде бы читал, но почему-то решил указать везде цифру 2, хотя до этого пробовал по другому, например вот так:
                    {set $resultsCargo = $_modx->runSnippet('!pdoResources', [
    'loadModels' => 'orders_external,orders_rails',
    'class' => 'BazOrders1External',
    'innerJoin' => '{ 
                    "Internal":{ "class":"BazOrders2Internal","on":"Internal.publishedby = BazOrders1External.publishedby" },
                    "Rails":{ "class":"BazOrders4Rails","on":"Rails.publishedby = BazOrders1External.publishedby" }
                     }',
    'tpl' => 'tpl.orders.row.my',
    'limit' => 0,
    'where' => "{ 'publishedby':{$user_id} }",
    'totalVar' => 'myTotalCargo',
    'showLog' => 1
])}При таком раскладе он считает все строки из таблицы BazOrders4Rails и множит их на количество строк в первой таблице BazOrders1External. Например если в BazOrders4Rails 3 строчки а в BazOrders1External 2, то он выведет 6 результатов, где эти 2 строчки повторяются по 3 раза. BazOrders2Internal тут вообще не выбирает ничего…            
                Так тоже самое выводит:
                    'innerJoin' => '{ 
                    "Internal":{ "class":"BazOrders2Internal","on":"Internal.publishedby = BazOrders1External.publishedby" }
                     }',
    'innerJoin' => '{ 
                    "Rails":{ "class":"BazOrders4Rails","on":"Rails.publishedby = BazOrders1External.publishedby" }
                     }',            
                leftJoin и rightJoin ведут себя точно так же. Значит дело в условии? Или в where?            
                    
                Добавил select, но ничего особенно не поменялось:
                    'select' => '{
                "BazOrders1External": "*",
                "Internal": "*",
                "Rails": "*"
                }
    ',            При таком раскладе он считает все строки из таблицы BazOrders4Rails и множит их на количество строк в первой таблице BazOrders1External.Всё правильно. А по твоему как должно быть?
В результате должны выбраться из всех подключаемых таблиц все строки где поле publishedby равно 2. Всё это дело нужно отсортировать по полям publishedon (timestamp-поле) в обратном порядке DESC.Я скорее всего чего-то недопонимаю, но результат должен быть таким.
                Если я правильно понимаю, эти таблицы друг с другом не связаны, просто из каждой таблицы нужно вывести определенные записи. 
Вижу 2 варианта. Или делать несколько запросов pdoResources по каждой таблице отдельно в массивы, а потом сливать в один. Тут будет проблема с сортировкой. Или сделать запрос с UNION через PDO.
                    Вижу 2 варианта. Или делать несколько запросов pdoResources по каждой таблице отдельно в массивы, а потом сливать в один. Тут будет проблема с сортировкой. Или сделать запрос с UNION через PDO.
Если я правильно понимаю, эти таблицы друг с другом не связаны, просто из каждой таблицы нужно вывести определенные записи.Да, правильно понимаешь.
Или сделать запрос с UNION через PDO.Да, значит буду строчить свой сниппет для этого. Спасибо за направление мысли!
                Пожалуйста. В помощь.            
                    
                Классно, спасибо большое! Очень полезная статья, ещё не дочитал но уже руки чешутся применить…            
                    
                Логика проста — выбирается BazOrders1External, к нему цепляется Internal и Rails. Если записей Internal или Rails для присоединения подходит больше, чем BazOrders1External, то выведутся они все.
А вот если указана группировка по какому-то полю, то это поле как бы уникальный ключ, и к нему будет выбирается только по одной записи из Internal и Rails.
В общем, как обычно. Нужно не pdoTools и его параметры учить, а SQL.
                    А вот если указана группировка по какому-то полю, то это поле как бы уникальный ключ, и к нему будет выбирается только по одной записи из Internal и Rails.
&groupby=`BazOrders1External.id`В общем, как обычно. Нужно не pdoTools и его параметры учить, а SQL.
                Спасибо Василию и Сергею за помощь. В итоге родился сниппет, в котором среди прочего и следующий код решающий мою задачу (я его упростил, оставил лишь принцип себе на будущее):
                    $sql = "SELECT * FROM modx_baz_orders_1_external WHERE publishedby = {$user_id} UNION
            SELECT * FROM modx_baz_orders_2_internal WHERE publishedby = {$user_id} UNION
            SELECT * FROM modx_baz_orders_3_sea WHERE publishedby = {$user_id}
            ORDER BY ".$sortby." ".$sortdir."
    ";
    $q = $modx->prepare($sql);
    $q->execute(array(0));
    $arr = $q->fetchAll(PDO::FETCH_ASSOC);
     foreach ($arr as $v) {
    	$arr = $v;
        $output .= $pdoTools->getChunk($tpl, $arr);
    }            
                Мда, убойная дискуссия у вас получилась:-) Вставлю пару слов, как пользоваться UNION. Во-первых, сначала ОБЯЗАТЕЛЬНО нужно найти общие колонки у всех таблиц. Для этого подходит: 
$classes = array('class1', 'class2', 'class3',...);
foreach($classes as $class) {
$select = arrey_intersoct($select, array_keys($modx->getFields($class)));
}
Во-вторых, также в цикле можно сгенерировать запросы, которые объединяются:
foreach($classes as $class) {
$c = $modx->newQuery($class);
$c->select($modx->getSelectColumns($class, $class, '', $select));
$c->where(array('published'=>2));
$from[] = c->prepare()->toSQL();
}
Ну и в конце все обьединить:
$query = «SELECT ». $modx->getSelectColumns($classes[0], 'orders', '', $select))." FROM ((".implode(') UNION (',$from).')) AS orders";
Далее уже запрос отправляется, как угодно.
            
                    $classes = array('class1', 'class2', 'class3',...);
foreach($classes as $class) {
$select = arrey_intersoct($select, array_keys($modx->getFields($class)));
}
Во-вторых, также в цикле можно сгенерировать запросы, которые объединяются:
foreach($classes as $class) {
$c = $modx->newQuery($class);
$c->select($modx->getSelectColumns($class, $class, '', $select));
$c->where(array('published'=>2));
$from[] = c->prepare()->toSQL();
}
Ну и в конце все обьединить:
$query = «SELECT ». $modx->getSelectColumns($classes[0], 'orders', '', $select))." FROM ((".implode(') UNION (',$from).')) AS orders";
Далее уже запрос отправляется, как угодно.
                            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.