Как выбрать данные из нескольких кастомных таблиц?
Мне нужно выбрать данные из нескольких кастомных таблиц через 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";
Далее уже запрос отправляется, как угодно.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.