我对findAll语句有以下标准
$with=array(
'tumor'=>array(
'select'=>false,
'joinType'=>'INNER JOIN',
),
'tumorLibraryType'=>array(
'select'=>false,
'joinType'=>'INNER JOIN',
'condition'=>'tumorLibraryType.id = 1 OR tumorLibraryType.id = 6',
),
'tumorPatient'=>array(
'select'=>false,
'joinType'=>'INNER JOIN',
)
);
$libPairs=LibraryPairs::model()->with($with)->findAll();
这些是相关的模型关系:
'tumor' => array(self::BELONGS_TO, 'Libraries', array('tumor_library'=>'id')),
'normal' => array(self::BELONGS_TO, 'Libraries', array('normal_library'=>'id')),
// making separate AR routes for tumor and normal. only tumor used currently
'tumorLibraryType'=>array(self::HAS_ONE,'LibraryTypes','','on'=>'tumor.library_type_id = tumorLibraryType.id'),
'tumorLibrariesIsolates'=>array(self::HAS_MANY,'LibrariesIsolates',array('id'=>'library_id'),'through'=>'tumor'),
'tumorSamplesIsolates'=>array(self::HAS_MANY,'SamplesIsolates',array('isolate_id'=>'isolate_id'),'through'=>'tumorLibrariesIsolates'),
'tumorSamples'=>array(self::HAS_MANY,'Samples',array('sample_id'=>'id'),'through'=>'tumorSamplesIsolates'),
'tumorPatient'=>array(self::HAS_ONE,'Patients',array('patient_id'=>'id'),'through'=>'tumorSamples'),
此代码生成以下sql:
SELECT `t`.`tumor_library` AS `t0_c0`, `t`.`normal_library` AS `t0_c1`, `t`.`created` AS `t0_c2`, `t`.`created_by` AS `t0_c3`, `t`.`last_modified` AS `t0_c4`, `t`.`last_modified_by` AS `t0_c5`, `tumor`.`library_type_id` AS `t1_c2`, `tumor`.`id` AS `t1_c0`
FROM `library_tumor_normal_pairs` `t`
INNER JOIN `library_types` `tumorLibraryType` ON (tumor.library_type_id = tumorLibraryType.id)
INNER JOIN `libraries` `tumor` ON (`t`.`tumor_library`=`tumor`.`id`)
LEFT OUTER JOIN `libraries_isolates` `tumorLibrariesIsolates` ON (`tumor`.`id`=`tumorLibrariesIsolates`.`library_id`)
LEFT OUTER JOIN `samples_isolates` `tumorSamplesIsolates` ON (`tumorLibrariesIsolates`.`isolate_id`=`tumorSamplesIsolates`.`isolate_id`)
LEFT OUTER JOIN `samples` `tumorSamples` ON (`tumorSamplesIsolates`.`sample_id`=`tumorSamples`.`id`)
INNER JOIN `patients` `tumorPatient` ON (`tumorSamples`.`patient_id`=`tumorPatient`.`id`)
WHERE (tumorLibraryType.id = 1 OR tumorLibraryType.id = 6)
但是那个sql会抛出一个错误:
“未找到列:1054未知列''on tumid.library_type_id'在'on子句'中。”
但是,如果我只是将sql查询中的肿瘤线移动到第一个连接语句,并手动运行查询,那么查询就可以了。
SELECT `t`.`tumor_library` AS `t0_c0`, `t`.`normal_library` AS `t0_c1`, `t`.`created` AS `t0_c2`, `t`.`created_by` AS `t0_c3`, `t`.`last_modified` AS `t0_c4`, `t`.`last_modified_by` AS `t0_c5`, `tumor`.`library_type_id` AS `t1_c2`, `tumor`.`id` AS `t1_c0`
FROM `library_tumor_normal_pairs` `t`
INNER JOIN `libraries` `tumor` ON (`t`.`tumor_library`=`tumor`.`id`)
INNER JOIN `library_types` `tumorLibraryType` ON (tumor.library_type_id = tumorLibraryType.id)
LEFT OUTER JOIN `libraries_isolates` `tumorLibrariesIsolates` ON (`tumor`.`id`=`tumorLibrariesIsolates`.`library_id`)
LEFT OUTER JOIN `samples_isolates` `tumorSamplesIsolates` ON (`tumorLibrariesIsolates`.`isolate_id`=`tumorSamplesIsolates`.`isolate_id`)
LEFT OUTER JOIN `samples` `tumorSamples` ON (`tumorSamplesIsolates`.`sample_id`=`tumorSamples`.`id`)
INNER JOIN `patients` `tumorPatient` ON (`tumorSamples`.`patient_id`=`tumorPatient`.`id`)
WHERE (tumorLibraryType.id = 1 OR tumorLibraryType.id = 6)
所以我的问题是,如何在Yii中控制“with”条件的sql连接顺序?可能吗?正如你可以看到我的'with'数组和关系在其他人之前有'肿瘤',但连接顺序没有保留。
答案 0 :(得分:2)
我遇到了类似的问题:Yii按照使SQL语句无效的顺序生成连接。例如,当您尝试编写依赖于$CDBCriteria->join
传递的关系中指定的表的自定义$CDBCriteria->with
时,会出现这种情况。发生这种情况是因为join
在CJoinQuery::__constructor
中处理,而所有“标准”连接(来自with
)都是由CJoinQuery::join
中的Yii生成的,即在构造函数之后。
不幸的是除了补丁之外没有解决方案。以下是我如何使用Yii副本的示例(代码以“原样”提供 - 请检查它是否适用于您的情况。)
首先,我们需要在CDbCriteria
中添加一个字段,该字段将打开/关闭新选项。
<强> CDbCriteria.php 强>
class CDbCriteria extends CComponent
{
...
/**
* @var string how to join with other tables. This refers to the JOIN clause in an SQL statement.
* For example, <code>'LEFT JOIN users ON users.id=authorID'</code>.
*/
public $join='';
/**
* Patch begins:
*/
public $joinreorder = false; // new option
...
其次,我们需要扩展CJoinQuery
(请注意,它位于CActiveFinder.php中):
<强> CActiveFinder.php 强>
class CJoinQuery
{
...
/**
* @var array list of join element IDs (id=>true)
*/
public $elements=array();
/**
* Patch begins:
*/
private $joinreorder = false; // the same new option
private $postjoins; // the variable to store our custom joins
...
现在我们可以改变CJoinQuery
构造函数:
CActiveFinder.php(续)
public function __construct($joinElement,$criteria=null)
{
if($criteria!==null)
{
$this->joinreorder = $criteria->joinreorder;
$this->selects[]=$joinElement->getColumnSelect($criteria->select);
$this->joins[]=$joinElement->getTableNameWithAlias();
if($this->joinreorder) //
{ //
$this->postjoins=$criteria->join; // new lines
} //
else //
{ //
$this->joins[]=$criteria->join;
} //
$this->conditions[]=$criteria->condition;
$this->orders[]=$criteria->order;
如果joinreorder
为true
,我们会在自己的新成员变量postjoins
中存储自定义联接。否则,一切都应该像以前一样工作。
现在CJoinQuery::createCommand
中的实际修复:
CActiveFinder.php(续)
public function createCommand($builder)
{
$sql=($this->distinct ? 'SELECT DISTINCT ':'SELECT ') . implode(', ',$this->selects);
$sql.=' FROM ' . implode(' ',$this->joins);
if($this->joinreorder) //
{ //
$sql .= $this->postjoins; // new lines
} //
...
最后,我们将自定义连接添加到SQL语句中,并将它们附加(不作为标准实现中的前缀)到Yii关系生成的其他连接。
现在我们可以像这样使用它:
$criteria = new CDbCriteria;
$criteria->joinreorder = true;
$criteria->with = array('product', 'shop');
$criteria->join = 'LEFT OUTER JOIN `shop2address` `s2a` ON (`shop`.`id` = `s2a`.`shop_id`)';
如果没有joinreorder = true
,则会在ON子句中生成错误,指出shop.id
是未知列,因为'shop'表尚未添加到SQL语句中。使用joinreorder = true
,它可以按预期工作。
对于仅使用with
并且生成不正确的连接序列的情况,应该应用更复杂的补丁。它涉及CJoinQuery::join
方法。它应该有一个可选参数$priority
,可以通过添加到CDbCriteria
中的相应成员再次填充。然后在CJoinQuery::join
中更改这些行:
$this->joins[$element->priority]=$element->getJoinCondition();
$this->joins[$element->priority]=$element->relation->join;
这允许根据指定的优先级以任意方式重新排序连接。
答案 1 :(得分:0)
此行看起来不正确:
'tumorLibraryType'=>array(self::HAS_ONE,'LibraryTypes','','on'=>'tumor.library_type_id = tumorLibraryType.id'),
也许它应该是
'tumorLibraryType'=>array(self::HAS_ONE,'LibraryTypes',array('id'=>'library_type_id'),'through'=>'tumor'),
答案 2 :(得分:0)
我有类似的问题
我有合并的标准:
$criteria = new CDbCriteria();
$criteria->with = [
'codebaseName' => [
'alias' => 'cn'
],
'codebaseProducer' => [
'alias' => 'cp'
],
'registrationDocumentLast' => [
'alias' =>'rdl'
]
];
它按照声明的顺序结束:
ORDER BY COALESCE(cn.name_our,cn.name_supplier), id DESC LIMIT 50
我没有明确指定id DESC的排序!
在玩了之后,我发现它来自关系registrationDocumentLast,它被定义为
'registrationDocumentLast' => [
self::HAS_ONE, RegistrationDocument::class, 'codebase_product_pharm_id',
'joinType' => 'LEFT JOIN',
'order' => 'id DESC'
],
查看订单密钥。从
改变它 'order' => 'id DESC'
到
'order' => 't.id DESC'
解决了问题