2017-02-02 3 views
0

Fragen Sie nicht, warum, aber ich habe diese Tabellen Situationen.Yii - LIKE auf konditionierten Join

enter image description here

Die Active Transport, Unternehmen, TransportDetail und TransportRow mit Yü klassischen strutture (BELONG_TO, HAS_MANY etc ...) im Zusammenhang

Unfortunaly, Regionen, Städte und Provinzen können nicht automatisch bezogen werden zu TransportDetails aufgrund konditionierten Joins basierend auf fromTypeId-Wert (es gibt eine toTypeId-Spalte zu).

Unfortunally Ich habe TransportRow mit einem Freitextfeld suchen, die in LIKE folgenden Bereichen suchen haben: „company.name“ (leicht, mit yii Beziehungen) „region.name oder city.name oder Provinz. name auf dem Wert der Spalte basiert“

um Company zu erreichen und kommen im allgemeinen jedes releation, im mit "mit" sintax

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

mit diesem auto-Join von company.name in suchen ODER ich fusionieren Basiskriterien mit einem OR-Kriterium:

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

Dies funktioniert perfekt.

Jetzt muss ich die Suche erweitern.

Diese Abfrage funktioniert gut, aber ich weiß nicht, ho, es auf Yii zu reproduzieren. Wenn Sie die Artikel auf die anderen drei Tabellen (Stadt, Provinz und Region) zu verbinden und in der in dem Zustand Kraft, um den Wert zu verwenden, nur wenn typeColumn den richtigen Wert hat, die Suche fein:

[ 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')) 

Ich habe nachzubilden versucht, kommen diese manuell in Yü Hinzufügen der Verknüpfung aber mergWith passieren, bevor Beziehung

beitreten
$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'); 

ich habe versucht MergeWith nach mit setzen, aber es funktioniert nicht:

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

der Fehler ist einfach. Wenn sich Regionen und Provinzen vor den anderen befinden, kann SQL die Spalte nicht in der ON-Bedingung finden, da sie im Besitz einer Tabelle ist, die nach ihnen angefügt ist.

Sorry für lange Post.

Irgendwelche Tipps?

+0

Sie möchten Beratung? Fix das Schema/Modell. Dann müssten Sie diese Frage nicht stellen, denn Sie hätten kein Problem. Sie spüren wahrscheinlich, dass der Tag kommt, an dem Sie es tun müssen, so dass der Tag heute genauso gut sein könnte. – Bohemian

+0

Ich kann die DB oder die Modelle nicht berühren. – MrMime

+0

Sie könnten Ihrem Vorgesetzten eine solche Arbeit vorschlagen und erklären, dass das aktuelle DB/Modell gebrochen ist und die weitere Verbesserung der Funktionen sehr schwierig sein wird, wenn es nicht erledigt ist. Unter [Technische Schulden] (https://en.m.wikipedia.org/wiki/Technical_debt) finden Sie eine vollständige Beschreibung Ihrer Situation. – Bohemian

Antwort

0

Ich habe eine gute Lösung gefunden. Zunächst wird -> mit Automatisierung immer nach dem expliziten JOIN der Anzeige hinzugefügt. So als ersten Schritt, übersetzte ich das MIT in einfachen JOIN und dann seinem Eintritt bei der alle drei Tabellen mit 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"; 

Der Schlüssel der CONCAT und IFNULL auf der Auswahl ist. Nur eine der drei externen Tabellen fügt eine Zeichenfolge hinzu, weil die beiden anderen Joins NULL zurückgeben (aufgrund von LINKER VERBINDUNG).

Also, wenn ein Zeilen als CITY, werde ich "ROM + null + null" => "ROME + '' + ''" => "ROME" haben

Damit kann ich auch ein Gridview bestellen mit allFrom und allTo Spalte.

Der nächste Schritt besteht darin, eine Ansicht zu erstellen, die diese Abfrage verwendet, um direkt der Haupttabelle beizutreten.

Tschüss!

Verwandte Themen