2017-02-02 5 views
0

Не спрашивайте, почему, но у меня есть эта ситуация с таблицами.Yii - LIKE на условном соединении

enter image description here

ActiveRecord Транспорт, Компания, TransportDetail и TransportRow связаны с Yii классическим Strutture (BELONG_TO, HAS_MANY и т.д ...)

сожелению, Регионы, Города и провинции не могут быть связаны автоматически to TransportDetails из-за условного соединения на основе значения fromTypeId (есть столбец toTypeId).

Unfortunally Я должен искать TransportRow со свободным текстовым полем, придется искать в LIKE следующих областях: «company.name» (легкий, с Yii отношений) «region.name или city.name или провинции. имя, основанное на значении столбца»

для достижения CompanyName и в целом присоединиться к каждой releation, Im, используя„с“синтаксисом

$criteria->with = array('transportDetail','transportDetail.transport','transportDetail.transport.company'); 

с этим автовхода, поиск по company.name ИЛИ я сливаю базовые критерии с критериями ИЛИ:

$criteriaORCompany = new CDbCriteria(); 
$criteriaORCompany->compare('company.name',$searchFilter->name,true,'OR'); 
$criteria->mergeWith($criteriaORCompany); 

Эта работа отлично.

Теперь я должен продолжить поиск.

Этот запрос работает нормально, но я не знаю, как его воспроизвести на Yii. Если вы добавите присоединиться к остальным трем таблицам (город, провинция и регион) и в состоянии где силы использовать значение только в том случае typeColumn имеет правильное значение, поиска работы штраф:

[ other join ...] 
LEFT OUTER JOIN regions cr on (cr.id = transportDetail.fromId) 
LEFT OUTER JOIN provinces cp on (cp.id = transportDetail.fromId) 
WHERE ((cr.name LIKE '%TEST%' and toTypeId = 'REGION') 
OR (cp.name LIKE '%TEST%' and toTypeId = 'PROVINCE')) 

Я пытался повторить это соединение в Yii добавление вручную объединения, но mergWith произойдет до отношения присоединиться

$criteriaLIKE = new CDbCriteria; 
$crt = Region::model()->tableName(); 
$cpt = Province::model()->tableName(); 
$criteriaLIKE->join .= 'LEFT OUTER JOIN '.$crt.' cr on (cr.id = transportDetail.fromId)'; 
$criteriaLIKE->join .= 'LEFT OUTER JOIN '.$cpt.' cp on (cp.id = transportDetail.fromId)'; 
$criteriaLIKE->addCondition("cr.name LIKE '%probe%' and toTypeId = 'REGION'",'OR'); 
$criteriaLIKE->addCondition("cp.name LIKE '%probe%' and toTypeId = 'PROVINCE'",'OR'); 

Я пытался поставить mergeWith после с, но он не работает:

$criteria->with = array('transportDetail','transportDetail.transport','transportDetail.transport.company'); 
$criteria->mergeWith($criteriaLIKE); 

ошибка просто. Когда регионы и область присоединились к другим, SQL не может найти столбец в состоянии ON, потому что принадлежащий ему, но подключенный после них.

Извините за длинный пост.

Любой совет?

+0

Вам нужен совет? Исправьте схему/модель. Тогда вам не придется задавать этот вопрос, потому что у вас не будет проблем. Вероятно, вы чувствуете, что наступает день, когда вам придется это делать, так что сегодня может быть и сегодня. – Bohemian

+0

Я не могу коснуться БД или моделей. – MrMime

+0

Вы можете предложить такую ​​работу своему руководителю, объяснив, что текущая модель DB/модель сломана, а дальнейшее улучшение функции будет очень затруднительным, если это не будет сделано. См. [Технический долг] (https://en.m.wikipedia.org/wiki/Technical_debt) для полного описания вашей ситуации. – Bohemian

ответ

0

Я нашел хорошее решение. Прежде всего, -> с автоматизацией всегда будет добавляться после объявления JOIN. Так как первый шаг, я перевел WITH в простой JOIN, а затем JOINED все три таблицы с LEFT OUTER

The criteria is used on transportRows ActiveRecord 

$criteria->join = " JOIN ".TransportDetail::MODEL()->tableName()." detail ON (detail.id = t.transportDetailId)"; 
    $criteria->join .= " JOIN ".Transport::MODEL()->tableName()." transport ON (transport.id = detail.transporttransportId)"; 
    $criteria->join .= " JOIN ".Company::MODEL()->tableName()." company ON (company.id = transport.companyId)"; 

    $criteria->join .= " LEFT JOIN ".City::model()->tableName()." cityFrom ON (cityFrom.id = detail.fromId AND detail.fromTypeId = 'CITY')"; 
    $criteria->join .= " LEFT JOIN ".City::model()->tableName()." cityTo ON (cityTo.id = detail.toId AND detail.toTypeId = 'CITY')"; 

    $criteria->join .= " LEFT JOIN ".Region::model()->tableName()." regionFrom ON (regionFrom.id = detail.fromId AND detail.fromTypeId = 'REGION')"; 
    $criteria->join .= " LEFT JOIN ".Region::model()->tableName()." regionTo ON (regionTo.id = detail.toId AND detail.toTypeId = 'REGION')"; 

    $criteria->join .= " LEFT JOIN ".Province::model()->tableName()." provinceFrom ON (provinceFrom.id = detail.fromId AND detail.fromTypeId = 'PROVINCE')"; 
    $criteria->join .= " LEFT JOIN ".Province::model()->tableName()." provinceTo ON (provinceTo.id = detail.toId AND detail.toTypeId = 'PROVINCE')"; 

    $criteria->select = "t.*, 
         CONCAT(IFNULL(locCompanyFrom.name,''),IFNULL(regionFrom.name,''),IFNULL(provinceFrom.name,'')) as allFrom, 
         CONCAT(IFNULL(locCompanyTo.name,''),IFNULL(regionTo.name,''),IFNULL(provinceTo.name,'')) as allTo"; 

Ключ CONCAT и IFNULL на выбор. Только одна из трех внешних таблиц добавит некоторую строку, потому что два других соединения возвратят NULL (из-за LEFT JOIN).

Так что, если строки как город, у меня будет «РИМ + нуль + нуль» => «РИМ +„“+„“» => «РИМ»

С этим я также можно заказать GridView с использованием allFrom и allTo.

Следующий шаг - создать представление, используя этот запрос, чтобы напрямую присоединиться к основной таблице.

До свидания!