我有一个模型item
与hasMany
模型有image
关系。在项目GridView
中,我有一列显示item
有多少张图像。我希望能够按此列进行排序,并且可能能够通过一个复选框进行过滤,以仅显示item
个而没有image
个。
我尝试向搜索模型添加检查以查询with
的{{1}}关系,并且我想为images
的计数位置添加一个andFilterWhere
小于输入值。但是我不确定具有这种逻辑的最佳方法,是否有更好的 Yii 方法可以根据该计数进行过滤?
更新
根据{{3}}的信息,我已经更新了image
模型,使其具有一种返回关系计数的方法。
然后我像这样更新搜索模型:
item
现在的问题是,上面的内容将产生类似以下的查询:
class ItemSearch extends Item
{
public $image_count;
/**
* @inheritdoc
*/
public function rules()
{
return [
[['id', 'product_id', 'manufacturer_id', 'scale_id', 'owner_id', 'quantity'], 'integer'],
[['sku_number', 'description', 'details', 'condition'], 'safe'],
[['price', 'sale_price', 'image_count'], 'number'],
];
}
/**
* @inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* @param array $params
*
* @return ActiveDataProvider
*/
public function search($params)
{
$query = Item::find();
$subQuery = Image::find()->select('item_id, COUNT(id) as image_count')->groupBy('item_id');
$query->leftJoin(['imageCount' => $subQuery], 'imageCount.item_id = id');
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->setSort([
'attributes' => [
'id',
'product_id',
'manufacturer_id',
'scale_id',
'owner_id',
'image_count' => [
'asc' => ['imageCount.image_count' => SORT_ASC],
'desc' => ['imageCount.image_count' => SORT_DESC],
'label' => 'Images'
]
]
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
if (!empty($this->id)) {
$query->andFilterWhere([
'id' => $this->id,
]);
}
if (!empty($this->product_id)) {
$query->andFilterWhere([
'product_id' => $this->product_id,
]);
}
if (!empty($this->manufacturer_id)) {
$query->andFilterWhere([
'manufacturer_id' => $this->manufacturer_id,
]);
}
if (!empty($this->scale_id)) {
$query->andFilterWhere([
'scale_id' => $this->scale_id,
]);
}
if (!empty($this->owner_id)) {
$query->andFilterWhere([
'owner_id' => $this->owner_id,
]);
}
if (!empty($this->image_count)) {
$query->andWhere(['is','imageCount.image_count',new \yii\db\Expression('null')]);
}
$query->andFilterWhere(['like', 'sku_number', $this->sku_number])
->andFilterWhere(['like', 'description', $this->description])
->andFilterWhere(['like', 'details', $this->details])
->andFilterWhere(['like', 'condition', $this->condition]);
return $dataProvider;
}
}
由于SELECT `item`.* FROM `item` LEFT JOIN (SELECT `item_id`, COUNT(id) as image_count FROM `image` GROUP BY `item_id`) `imageCount` ON imageCount.item_id = id WHERE `imageCount`.`image_count`=0
具有0个items
的问题将不再显示(并且选中该框不会显示任何内容),因为联接在image
表中找不到该ID的任何内容< / p>
答案 0 :(得分:3)
您应检查WHERE imageCount.image_count IS NULL
而不是WHERE imageCount.image_count=0
,因为那些没有任何相关图像的行将在null
下显示为image_count
,并更改条件来自
$query->andFilterWhere(['imageCount.image_count' => 0]);
到
$query->andWhere(['is','imageCount.image_count',new \yii\db\Expression('null')]);`
您的查询应生成为
SELECT `item`.* FROM `item`
LEFT JOIN
(
SELECT `item_id`, COUNT(id) as image_count
FROM `image`
GROUP BY `item_id`
) `imageCount`
ON imageCount.item_id = id
WHERE `imageCount`.`image_count` is NULL
更新
由于您仍然面临问题,所以我认为我有空闲时间来发现此问题,因此我提出了以下建议
在过滤图像计数为0的项目时遇到问题,但我没有确切的架构,但在下面的示例中,我将使用Shoots
和联结表ShootTag
模型中它们的相关标签
Shoots
下面是模式和数据的示例
+----+------------+--------+------------+
| id | name | active | shoot_type |
+----+------------+--------+------------+
| 1 | aslam omer | 1 | modeling |
| 2 | asif | 1 | modeling |
| 3 | saleem | 1 | modeling |
| 4 | sajid | 1 | modeling |
| 5 | tasleem | 1 | modeling |
| 6 | tehseen | 1 | modeling |
| 7 | amjad | 1 | modeling |
| 8 | shaban | 1 | modeling |
| 9 | irfan | 1 | modeling |
+----+------------+--------+------------+
ShootTags
下面是模式和数据的示例
+----------+--------+
| shoot_id | tag_id |
+----------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 3 | 1 |
| 4 | 1 |
| 4 | 4 |
+----------+--------+
现在考虑上述表格和数据,我有一个名称为ShootsSearch
的搜索模型,该模型用于显示所有芽,并且我想针对{内保存的每个芽显示标签的数量{1}}模型。
我没有添加GridView的代码,因为它无关紧要,我的搜索模型ShootTag
具有以下搜索方法,该方法可以正确地对芽标签模型中的芽进行计数。
与您的代码不同的是,我在第一个查询中使用ShootsSearch
模型,而不是在使用ShootsSearch
时应使用Shoots
模型,{
Item::find();
的别名
然后在主查询中的行ItemSearch::find();
上需要将空值显示为0,以便可以在此处使用条件选择。
然后,您需要检查image_count
以应用new Expression('if(st.totalTags is NOT NULL,st.totalTags,0) as totalTags')
,因为if ($this->totalTags == '0') {
的实际值为$query->andWhere(['IS', 'totalTags', new Expression('null')]);
,其中没有针对任何{ {1}},在其他部分,您将使用null
这在您希望看到下面的图像的所有三种情况下都能正常工作
首次使用默认视图
搜索总标签数为4的芽
搜索TotalTags计数为0的芽
您应在代码中替换以下内容
totalTags
和Shoot
。query->andFilterWhere(['=', 'totalTags', $this->totalTags]);
和public $totalTags
。public $image_count
和ShootTags
。Image
和shoot_id
/ item_id
。这是搜索模型,代码已通过测试并且可以正常工作。
ShootsSearch
答案 1 :(得分:1)
我的理解是,您需要计算关联表中的数据量,并根据统计信息进行排序和过滤。
然后您的ItemSearch::search()
方法应该可以更改为此:
public function search($params)
{
$query = Item::find()->select('*, (select count(*) from image where image.item_id = item.id) as image_count'); // If the table name of your Image table is image, if the table name of your Item table is item
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->setSort([
'attributes' => [
'id',
'product_id',
'manufacturer_id',
'scale_id',
'owner_id',
'image_count'
]
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
if (!empty($this->id)) {
$query->andFilterWhere([
'id' => $this->id,
]);
}
if (!empty($this->product_id)) {
$query->andFilterWhere([
'product_id' => $this->product_id,
]);
}
if (!empty($this->manufacturer_id)) {
$query->andFilterWhere([
'manufacturer_id' => $this->manufacturer_id,
]);
}
if (!empty($this->scale_id)) {
$query->andFilterWhere([
'scale_id' => $this->scale_id,
]);
}
if (!empty($this->owner_id)) {
$query->andFilterWhere([
'owner_id' => $this->owner_id,
]);
}
if (!empty($this->image_count)) {
$query->andWhere([
'image_count' => $this->image_count,
]);
}
$query->andFilterWhere(['like', 'sku_number', $this->sku_number])
->andFilterWhere(['like', 'description', $this->description])
->andFilterWhere(['like', 'details', $this->details])
->andFilterWhere(['like', 'condition', $this->condition]);
return $dataProvider;
}
但是,如果您的image_count通常需要计算和统计信息,并且您的数据量很大,那么建议您将此字段重新定义为项目表。
更新:
我的错,聚合字段无法通过where条件过滤,但是您可以使用具有以下条件的
$query->andFilterHaving([
'image_count' => $this->image_count,
]);