Как выбрать данные из нескольких кастомных таблиц?

Мне нужно выбрать данные из нескольких кастомных таблиц через pdoResources, но не получается настроить Join-ы правильно.
Есть несколько кастомных таблиц с одинаковой структурой полей и с сгенерированными моделями.
Данные из одной таблицы выводятся легко:
[[!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.

Что я неправильно делаю?
Василий Столейков
10 февраля 2016, 18:32
modx.pro
7
3 200
0
Поблагодарить автора Отправить деньги

Комментарии: 17

Волков Николай
11 февраля 2016, 04:08
0
Что-то мне подсказывает, что тебе нужно воспользоваться UNION, а не JOIN.
    Василий Столейков
    11 февраля 2016, 07:55
    0
    Точно, очень даже логично…
    Только вот как использовать UNION в pdoResources?..
    Или прийдется писать свой сниппет для вывода?
    Василий Наумкин
    11 февраля 2016, 08:41
    +1
    &innerJoin=`{ 
    	"BazOrders2Internal":{ "alias":"Internal","on":"Internal.publishedby = \"2\"" },
    	"BazOrders4Rails":{ "alias":"Rails","on":"Rails.publishedby = \"2\"" }
    }`
    И к чему здесь таблицы присоединяются? К цифре 2?

    Всё же расписано, почему не прочитать? docs.modx.pro/components/pdotools/classes/pdofetch#Метод-addJoins
      Василий Столейков
      11 февраля 2016, 09:06
      0
      Вроде бы читал, но почему-то решил указать везде цифру 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 тут вообще не выбирает ничего…
        Василий Столейков
        11 февраля 2016, 09:07
        0
        Так тоже самое выводит:
        'innerJoin' => '{ 
                            "Internal":{ "class":"BazOrders2Internal","on":"Internal.publishedby = BazOrders1External.publishedby" }
                             }',
            'innerJoin' => '{ 
                            "Rails":{ "class":"BazOrders4Rails","on":"Rails.publishedby = BazOrders1External.publishedby" }
                             }',
          Василий Столейков
          11 февраля 2016, 09:08
          0
          leftJoin и rightJoin ведут себя точно так же. Значит дело в условии? Или в where?
            Василий Столейков
            11 февраля 2016, 09:14
            0
            Добавил select, но ничего особенно не поменялось:
            'select' => '{
                            "BazOrders1External": "*",
                            "Internal": "*",
                            "Rails": "*"
                            }
                ',
              Сергей Шлоков
              11 февраля 2016, 09:21
              0
              При таком раскладе он считает все строки из таблицы BazOrders4Rails и множит их на количество строк в первой таблице BazOrders1External.
              Всё правильно. А по твоему как должно быть?
                Василий Столейков
                11 февраля 2016, 09:23
                0
                В результате должны выбраться из всех подключаемых таблиц все строки где поле publishedby равно 2. Всё это дело нужно отсортировать по полям publishedon (timestamp-поле) в обратном порядке DESC.
                Я скорее всего чего-то недопонимаю, но результат должен быть таким.
                  Сергей Шлоков
                  11 февраля 2016, 09:28
                  +1
                  Если я правильно понимаю, эти таблицы друг с другом не связаны, просто из каждой таблицы нужно вывести определенные записи.
                  Вижу 2 варианта. Или делать несколько запросов pdoResources по каждой таблице отдельно в массивы, а потом сливать в один. Тут будет проблема с сортировкой. Или сделать запрос с UNION через PDO.
                    Василий Столейков
                    11 февраля 2016, 09:31
                    0
                    Если я правильно понимаю, эти таблицы друг с другом не связаны, просто из каждой таблицы нужно вывести определенные записи.
                    Да, правильно понимаешь.
                    Или сделать запрос с UNION через PDO.
                    Да, значит буду строчить свой сниппет для этого. Спасибо за направление мысли!
              Василий Наумкин
              11 февраля 2016, 10:27
              +1
              Логика проста — выбирается BazOrders1External, к нему цепляется Internal и Rails. Если записей Internal или Rails для присоединения подходит больше, чем BazOrders1External, то выведутся они все.

              А вот если указана группировка по какому-то полю, то это поле как бы уникальный ключ, и к нему будет выбирается только по одной записи из Internal и Rails.
              &groupby=`BazOrders1External.id`

              В общем, как обычно. Нужно не pdoTools и его параметры учить, а SQL.
            Василий Столейков
            11 февраля 2016, 15:48
            0
            Спасибо Василию и Сергею за помощь. В итоге родился сниппет, в котором среди прочего и следующий код решающий мою задачу (я его упростил, оставил лишь принцип себе на будущее):
            $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);
                }
              Волков Николай
              13 февраля 2016, 05:34
              0
              Мда, убойная дискуссия у вас получилась:-) Вставлю пару слов, как пользоваться 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";
              Далее уже запрос отправляется, как угодно.
              Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
              17