May 02 2009

Left Join с несколькими условиями для Propel Criteria

Category: Symfonyingvar @ 19:16

Бывают ситуации, когда нужно получить запрос c оператором Left Join указав несколько условных выражений. Например:

SELECT * FROM news
LEFT JOIN news_type ON news.type_id = news_type.id AND YEAR(news.published_at) = YEAR(NOW())
WHERE news.is_published = 1 AND ...
LIMIT 10

Используя стандартную конструкцию Propel Criteria, получаем следующий код:

$c = new Criteria();
$c->add(NewsPeer::IS_PUBLISHED, true);
$c->addJoin(NewsPeer::TYPE_ID, NewsTypePeer::ID, Criteria::LEFT_JOIN);
$c->add(NewsPeer::DATE, "YEAR(" . NewsPeer::PUBLISHED_AT. ") = YEAR(NOW())", Criteria::CUSTOM);
....

Но результат не будет соответствовать нашему условию и это можно увидеть в сгененированном SQL-коде:

SELECT * FROM news
LEFT JOIN news_type ON news.type_id = news_type.id
WHERE news.is_published = 1 AND YEAR(news.published_at) = YEAR(NOW()) ...
LIMIT 10

В Propel 1.3 появилась возможность указать несколько условий для оператора Join. Правильный код будет таков:

$c = new Criteria();
$c->add(NewsPeer::IS_PUBLISHED, true);

$c->addJoin(
  array(NewsPeer::TYPE_ID, "YEAR(" .  NewsPeer::PUBLISHED_AT. ")"),
  array(NewsTypePeer::ID, "YEAR(NOW())"),
  Criteria::LEFT_JOIN
);

....

Источник: Propel 1.3:: More on Criteria:: Joins

Tags: ,

7 Responses to “Left Join с несколькими условиями для Propel Criteria”

  1. broderix says:

    Сам с этим сталкивался, код такой же)
    А вы можете сказать почему нужно указывать именно перекрестно:
    $c->addJoin(
    array(NewsPeer::TYPE_ID, «YEAR(» . NewsPeer::PUBLISHED_AT. «)»),
    array(NewsTypePeer::ID, «YEAR(NOW())»),
    Criteria::LEFT_JOIN
    );
    а не так:
    $c->addJoin(
    array(NewsPeer::TYPE_ID,NewsTypePeer::ID),
    array( «YEAR(» . NewsPeer::PUBLISHED_AT. «)», «YEAR(NOW())»),
    Criteria::LEFT_JOIN
    );
    что мне кажется логичнее ?

    • ilya says:

      addMultipleJoin как раз так и работает :)

      • ingvar says:

        Все верно, только метод этот появился в Propel 1.4 :)

        • Зариман says:

          Ох уж эти LEFT JOIN. Один раз наткнулся не непонятный случай, так и не смог понять в чем дело.

          SELECT t1.field1, t2.field2
          FROM t1 LEFT JOIN t2 ON t1.id = t2.id

          привело к повисанию MySQL на таблицах t1 и t2, содержащих более 10000 записей каждая

          в тоже время

          SELECT t1.field1, t2.field2
          FROM t1, t2
          WHERE t1.id = t2.id

          отработало мгновенно, хотя декартово произведение по логике намного затратнее.

  2. ingvar says:

    ну это уже к разработчикам :). Хотя так действительно логичнее сделать, а главное удобнее.

  3. Павел says:

    Спасибо! Наконец-то…

  4. Павел says:

    А как быть с более сложными условиями внутри INNER JOIN?
    Например, Criteria::CUSTOM, или когда более сложное логическое условие вместе с OR?

Leave a Reply to broderix