mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-03 22:32:40 +08:00
Fixes #1809: Added support for building "EXISTS" and "NOT EXISTS" query conditions
This commit is contained in:
@ -55,6 +55,7 @@ Yii Framework 2 Change Log
|
||||
- Enh #1681: Added support for automatically adjusting the "for" attribute of label generated by `ActiveField::label()` (qiangxue)
|
||||
- Enh #1706: Added support for registering a single JS/CSS file with dependency (qiangxue)
|
||||
- Enh #1773: keyPrefix property of Cache is not restricted to alnum characters anymore, however it is still recommended (cebe)
|
||||
- Enh #1809: Added support for building "EXISTS" and "NOT EXISTS" query conditions (abdrasulov)
|
||||
- Enh #1852: ActiveRecord::tableName() now returns table name using DbConnection::tablePrefix (creocoder)
|
||||
- Enh: Added `favicon.ico` and `robots.txt` to default application templates (samdark)
|
||||
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
|
||||
|
||||
@ -799,6 +799,8 @@ class QueryBuilder extends \yii\base\Object
|
||||
'NOT LIKE' => 'buildLikeCondition',
|
||||
'OR LIKE' => 'buildLikeCondition',
|
||||
'OR NOT LIKE' => 'buildLikeCondition',
|
||||
'EXISTS' => 'buildExistsCondition',
|
||||
'NOT EXISTS' => 'buildExistsCondition',
|
||||
];
|
||||
|
||||
if (!is_array($condition)) {
|
||||
@ -1071,4 +1073,21 @@ class QueryBuilder extends \yii\base\Object
|
||||
|
||||
return implode($andor, $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SQL expressions with the `EXISTS` operator.
|
||||
* @param string $operator the operator to use (e.g. `EXISTS` or `NOT EXISTS`)
|
||||
* @param array $operands contains only the one element. It is sub-query
|
||||
* @param array $params the binding parameters to be populated
|
||||
* @return string the generated SQL expression
|
||||
*/
|
||||
public function buildExistsCondition($operator, $operands, &$params)
|
||||
{
|
||||
$subQuery = $operands[0];
|
||||
list($subQuerySql, $subQueryParams) = $this->build($subQuery);
|
||||
foreach ($subQueryParams as $name => $value) {
|
||||
$params[$name] = $value;
|
||||
}
|
||||
return "$operator ($subQuerySql)";
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace yiiunit\framework\db;
|
||||
|
||||
use yii\db\Query;
|
||||
use yii\db\QueryBuilder;
|
||||
use yii\db\Schema;
|
||||
use yii\db\mysql\QueryBuilder as MysqlQueryBuilder;
|
||||
@ -130,4 +131,86 @@ class QueryBuilderTest extends DatabaseTestCase
|
||||
$tableSchema = $qb->db->getSchema()->getTableSchema($tableName);
|
||||
$this->assertEquals(0, count($tableSchema->primaryKey));
|
||||
}
|
||||
|
||||
public function testBuildWhereExists()
|
||||
{
|
||||
$expectedQuerySql = "SELECT `id` FROM `TotalExample` `t` WHERE EXISTS (SELECT `1` FROM `Website` `w`)";
|
||||
$expectedQueryParams = null;
|
||||
|
||||
$subQuery = new Query();
|
||||
$subQuery->select('1')
|
||||
->from('Website w');
|
||||
|
||||
$query = new Query();
|
||||
$query->select('id')
|
||||
->from('TotalExample t')
|
||||
->where(['exists', $subQuery]);
|
||||
|
||||
list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query);
|
||||
$this->assertEquals($expectedQuerySql, $actualQuerySql);
|
||||
$this->assertEquals($expectedQueryParams, $actualQueryParams);
|
||||
}
|
||||
|
||||
public function testBuildWhereNotExists()
|
||||
{
|
||||
$expectedQuerySql = "SELECT `id` FROM `TotalExample` `t` WHERE NOT EXISTS (SELECT `1` FROM `Website` `w`)";
|
||||
$expectedQueryParams = null;
|
||||
|
||||
$subQuery = new Query();
|
||||
$subQuery->select('1')
|
||||
->from('Website w');
|
||||
|
||||
$query = new Query();
|
||||
$query->select('id')
|
||||
->from('TotalExample t')
|
||||
->where(['not exists', $subQuery]);
|
||||
|
||||
list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query);
|
||||
$this->assertEquals($expectedQuerySql, $actualQuerySql);
|
||||
$this->assertEquals($expectedQueryParams, $actualQueryParams);
|
||||
}
|
||||
|
||||
public function testBuildWhereExistsWithParameters()
|
||||
{
|
||||
$expectedQuerySql = "SELECT `id` FROM `TotalExample` `t` WHERE (EXISTS (SELECT `1` FROM `Website` `w` WHERE (w.id = t.website_id) AND (w.merchant_id = :merchant_id))) AND (t.some_column = :some_value)";
|
||||
$expectedQueryParams = [':some_value' => "asd", ':merchant_id' => 6];
|
||||
|
||||
$subQuery = new Query();
|
||||
$subQuery->select('1')
|
||||
->from('Website w')
|
||||
->where('w.id = t.website_id')
|
||||
->andWhere('w.merchant_id = :merchant_id', [':merchant_id' => 6]);
|
||||
|
||||
$query = new Query();
|
||||
$query->select('id')
|
||||
->from('TotalExample t')
|
||||
->where(['exists', $subQuery])
|
||||
->andWhere('t.some_column = :some_value', [':some_value' => "asd"]);
|
||||
|
||||
list($actualQuerySql, $queryParams) = $this->getQueryBuilder()->build($query);
|
||||
$this->assertEquals($expectedQuerySql, $actualQuerySql);
|
||||
$this->assertEquals($expectedQueryParams, $queryParams);
|
||||
}
|
||||
|
||||
public function testBuildWhereExistsWithArrayParameters()
|
||||
{
|
||||
$expectedQuerySql = "SELECT `id` FROM `TotalExample` `t` WHERE (EXISTS (SELECT `1` FROM `Website` `w` WHERE (w.id = t.website_id) AND ((`w`.`merchant_id`=:qp0) AND (`w`.`user_id`=:qp1)))) AND (`t`.`some_column`=:qp2)";
|
||||
$expectedQueryParams = [':qp0' => 6, ':qp1' => 210, ':qp2' => 'asd'];
|
||||
|
||||
$subQuery = new Query();
|
||||
$subQuery->select('1')
|
||||
->from('Website w')
|
||||
->where('w.id = t.website_id')
|
||||
->andWhere(['w.merchant_id' => 6, 'w.user_id' => '210']);
|
||||
|
||||
$query = new Query();
|
||||
$query->select('id')
|
||||
->from('TotalExample t')
|
||||
->where(['exists', $subQuery])
|
||||
->andWhere(['t.some_column' => "asd"]);
|
||||
|
||||
list($actualQuerySql, $queryParams) = $this->getQueryBuilder()->build($query);
|
||||
$this->assertEquals($expectedQuerySql, $actualQuerySql);
|
||||
$this->assertEquals($expectedQueryParams, $queryParams);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user