Mysql 如何在Yii CDbCriteria中控制sql连接顺序;加上;
对于findAll语句,我有以下标准Mysql 如何在Yii CDbCriteria中控制sql连接顺序;加上;,mysql,activerecord,join,yii,database-relations,Mysql,Activerecord,Join,Yii,Database Relations,对于findAll语句,我有以下标准 $with=array( 'tumor'=>array( 'select'=>false, 'joinType'=>'INNER JOIN', ), 'tumorLibraryType'=>array( 'select'=>false, 'joinType'=>'INNER JOIN', 'condition'=>'tumorLibraryType.id
$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子句”中的未知列“tumor.library\u type\u id”。
但是,如果我简单地将sql查询中的肿瘤行上移到第一个join语句,并手动运行查询,那么查询就会工作
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'数组和关系在其他数组之前有'tum',但是连接顺序没有保留。这行看起来不正确:
'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'),
我遇到了一个类似的问题:Yii生成连接的顺序使得SQL语句无效。例如,当您试图编写依赖于通过
$CDBCriteria->with
传递的关系中指定的表的自定义$CDBCriteria->join
时,就会出现这种情况。这是因为join
在CJoinQuery::\uu构造函数
中处理,而所有的“标准”联接(从到)都是由Yii在CJoinQuery::join
中生成的,即在构造函数之后
不幸的是,除了补丁之外,没有其他解决方案。以下是我如何在我的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
...
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中):
CActiveFinder.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
...
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(续)
如果joinreorder
为true
我们将自定义联接存储在新成员变量postjoins
中。否则,所有这些都应该像以前一样工作
现在是CJoinQuery::createCommand
中的实际修复:
CActiveFinder.php(续)
最后,我们将自定义联接添加到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;
这允许根据指定的优先级以任意方式重新排序联接。伙计们,我想我来晚了
我也有类似的问题
我对合并有以下标准:
$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排序
在玩了一番之后,我发现它来自关系注册DocumentLast,它被定义为
'registrationDocumentLast' => [
self::HAS_ONE, RegistrationDocument::class, 'codebase_product_pharm_id',
'joinType' => 'LEFT JOIN',
'order' => 'id DESC'
],
看看订单键。从
'order' => 'id DESC'
到
解决了当多个关系“通过”同一个关系时出现“非唯一表别名”错误的问题。确定。但是您可以指定别名:这并不能解决表别名不唯一的问题,因为它会使用相同的别名创建额外的联接,或者需要冗余联接和“通过”关系,这会降低速度。这是一个记录在案的问题,上面的解决方案是最有效的。我最终以另一种方式解决了这个问题,但如果有人知道如何使用“with”来控制连接顺序,我仍然想知道如何。这太好了。我还没有测试过你的解决方案,但你是否在Yii论坛上发布过?它可能会被合并到未来的版本中。@glyph当它完成时,我可能会发布一个解决方案,这意味着用
s在中重新排序。
'order' => 't.id DESC'