ох уж это where

Хочу составить условие для нахождения товаров, по передаваемым значениям опций.
Вот часть кода
$q = $modx->newQuery('msProductOption');
$q->innerJoin('msProduct', 'msProduct', 'msProduct.id=msProductOption.product_id');
$q->where(array('msProductOption.key' => 'height', 'msProductOption.value:IN'=> [152]));
$q->where(array(
    'msProductOption.key' => 'presure', 
    'msProductOption.value:IN'=> [900],

));
Идея в том, чтобы отобрать товары у которых И высота равна 152 и одновременно и давление 900.
Данный код в виде SQL выглядит так
SELECT DISTINCT(msProductOption.value), msProduct.id FROM `modx_ms2_product_options` AS `msProductOption` JOIN `modx_site_content` `msProduct` ON msProduct.id=msProductOption.product_id WHERE ( ( `msProductOption`.`key` = 'height' AND `msProductOption`.`value` IN ('152') ) AND ( `msProductOption`.`key` = 'presure' AND `msProductOption`.`value` IN ('900') ) ) ORDER BY msProductOption.value ASC
и ничего не возвращает, как в modx так и напрямую выполненный в mysql.
Хотя товар есть, который должен попасть под эту выборку.
Заменяю AND на OR
WHERE ( ( `msProductOption`.`key` = 'height' AND `msProductOption`.`value` IN ('152') ) OR ( `msProductOption`.`key` = 'presure' AND `msProductOption`.`value` IN ('900') ) )
получаю вполне логичный результат — все товару и кого высота 152 и все товары у кого давление 900

Не хочу дальше вас запутывать своими рассказами, лучше к вопросу
— как корректно ставить where для разных вариантов? Чтобы скажем отобрать только товары у кого высота строго 152 и при этом и давление строго 900? Потому как я наглядно вижу, что два раза переданный where объединяется через AND, хотя вот тут написано docs.modx.com/current/en/extending-modx/xpdo/class-reference/xpdoquery/xpdoquery.where
// two arrays used to contain the OR statement within the listed conditions
то есть два массива where по умолчанию соединяются через OR, а на практике не так?
— как сделать чтобы два передаваемых массива where объединялись через OR вместо AND?
спасибо.
Александр Мельник
06 мая 2020, 13:19
modx.pro
641
0

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

Баха Волков
06 мая 2020, 13:58
0
Так ты же выбираешь опции

как сделать чтобы два передаваемых массива where объединялись через OR вместо AND?
Вот по той же ссылке которую ты указал есть ответ на твой вопрос:

$query = $xpdo->newQuery('Box');
$query->where(array('width' => 15));
$query->where(array('width' => 10),xPDOQuery::SQL_OR); // you can use orCondition here as well
$boxes = $xpdo->getCollection('Box',$query);

или

$query = $xpdo->newQuery('Box');
$query->where(array(
   array( // two arrays used to contain the OR statement within the listed conditions
      'width' => 15
   ),
   array(
      'width' => 10
   )
),xPDOQuery::SQL_OR); // use one array if no additional where statements are used.
$boxes = $xpdo->getCollection('Box',$query);

или

$query = $xpdo->newQuery('Box');
$query->where(array(
   array(
      'width' => 15
   ),
   array(
      'OR:width:=' => 10
   )
));
$boxes = $xpdo->getCollection('Box',$query);
    Александр Мельник
    06 мая 2020, 14:48
    0
    Так ты же выбираешь опции
    это был не полный код, полный выглядит так
    $q = $modx->newQuery('msProductOption');
    $q->innerJoin('msProduct', 'msProduct', 'msProduct.id=msProductOption.product_id');
    $q->where(array('msProductOption.key' => 'height', 'msProductOption.value:IN'=> [152]));
    $q->where(array(
        'msProductOption.key' => 'presure', 
        'msProductOption.value:IN'=> [900],
        
    
    
    ));
    
    $q->sortby('msProductOption.value','ASC');
    $q->select('DISTINCT(msProductOption.value), msProduct.id');
    //$q->where(array('msProductOption.key' => $key));
    if (!empty($category)) {
        $ids = $modx->getChildIds($category);
        $ids[] = $category;
        $q->innerJoin('msCategory', 'msCategory', 'msCategory.id=msProduct.parent');
        $q->where(array('msCategory.id:IN' => $ids));
    }
    
    $q->prepare();
    print_r($q->toSQL());
    Я пробовал второй и третий код, который вы написали — они не сработали и выдавали ошибки синтаксиса sql. Возможно это связано с тем, что в примерах условие простое КЛЮЧ — Значение. А у меня условие (Опция называется вот так и ее значение вот такое — это первый where и второй — опция называется как-то иначе и ее значение вот такое).
    Тоесть как-то так
    $q->where(array(
        'OR:msProductOption.key' => 'presure', 
        'msProductOption.value:IN'=> [900],
    
    ));
    приводит к ошибке.
    А вот первый код, где можно передать дополнительно константу — я пропустил, спасибо.

    Но по сути, на данный момент я считаю что sql запрос получается то правильным, по крайней мере составляй я его сам, составил бы так же и два условия ДОЛЖНЫ соединятся через AND, если я хочу найти товар у которого одна опция равна чему то и вторая тоже равна чему то. Но почему-то этого не происходит, как только два условия
    WHERE ( ( `msProductOption`.`key` = 'height' AND `msProductOption`.`value` IN ('152') ) AND ( `msProductOption`.`key` = 'presure' AND `msProductOption`.`value` IN ('900') ) )
    идут через AND то результат выборки пуст, хотя точно есть товар у котороо высота 154 и давление 900.

    В общем, где-то торможу я)
      Артем
      07 мая 2020, 00:57
      0
      идут через AND то результат выборки пуст, хотя точно есть товар у котороо высота 154 и давление 900.
      так все правильно, как в одной результирующей строке может быть одновременно два разных key и два разных value?
      если ты посмотришь EXPLAIN своего запроса, то наверняка увидишь Impossible where
      тебе нужно приджойнить таблицу опций еще раз, тогда ты сможешь выбирать из одной один ключ и значение, а из другой — другие

      $c = $modx->newQuery(msProduct::class, [
          'Height.key' => 'height',
          'Height.value' => '152',
          'Pressure.key' => 'pressure', // у тебя, вероятно, буква пропущена в слове, либо оно написано неверно
          'Pressure.value' => '900',
      ]);
      $c->select(['msProduct.id', 'msProduct.pagetitle']);
      $c->leftJoin('msProductOption', 'Height', 'Height.product_id = msProduct.id');
      $c->leftJoin('msProductOption', 'Pressure', 'Pressure.product_id = msProduct.id');
      if ($c->prepare() && $c->stmt->execute()) {
          return $c->stmt->fetchAll(PDO::FETCH_KEY_PAIR);
      }
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
4