如何 select 只有那些至少有一个关联记录的记录?
How to select only those records that have at least one associated record?
我有以下关联:Orders
belongsTo Sites
我执行以下查询:
$sites = $this->Sites->find('all')
->select(['id', 'name'])
->contain([
'Users' => function ($q) {
return $q->select(['id', 'owner_id', 'firstname', 'lastname']);
},
'Orders' => function ($q) {
return $q->where(['status >' => 0]);
},
'Orders.Agplans'
])
->matching('Users', function ($q) use($owner_id)
{
return $q->where([
'Users.owner_id' => $owner_id
]);
})
->all();
但是大多数网站都没有订单,所以我得到了一些结果:
(int) 100 => object(App\Model\Entity\Site) {
'id' => (int) 7966,
'name' => 'Site example',
'orders' => [],
'users' => [
(int) 0 => object(App\Model\Entity\User) {
...
是否可以在查询中指定我只想要 sites
而不是空 orders
?
因为你有一个 hasMany
关联,你必须采取额外的措施来包含 Orders
。
使用内部联接
您可以使用 INNER
联接,这将 select 只有那些存在匹配顺序的行。出于过滤目的,这可以使用 Query::innerJoinWith()
轻松完成,它类似于 Query::matching()
,但它不会加载任何结果。
$sites = $this->Sites
->find('all')
->select(['id', 'name'])
// ...
->innerJoinWith('Orders', function ($q) {
return $q->where(['Orders.status >' => 0]);
})
->group(['Sites.id']) // may or may not be necessary
->all();
像您一样使用匹配
您已经在使用 Query::matching()
作为 Users
,所以我假设您知道它的作用...过滤。为 Orders
添加进一步的匹配也是一种选择,但是它会获取额外的数据。
$sites = $this->Sites
->find('all')
->select(['id', 'name'])
// ...
->matching('Orders', function ($q) {
return $q->where(['Orders.status >' => 0]);
})
->group(['Sites.id']) // may or may not be necessary
->all();
最后但同样重要的是,使用计数器缓存
使用正确索引的计数器缓存可能是性能最佳的选项,因为过滤将通过同一 table 中的列完成。
您可以在 Orders
模型中使用适当的条件定义它,然后只需在查询中使用 where()
,例如
$this->addBehavior('CounterCache', [
'Sites' => [
'active_orders_count' => [
'conditions' => ['Orders.status >' => 0]
]
]
]);
$sites = $this->Sites
->find('all')
->select(['id', 'name'])
// ...
->where([
'active_orders_count >' => 0
])
->all();
另见
我有以下关联:Orders
belongsTo Sites
我执行以下查询:
$sites = $this->Sites->find('all')
->select(['id', 'name'])
->contain([
'Users' => function ($q) {
return $q->select(['id', 'owner_id', 'firstname', 'lastname']);
},
'Orders' => function ($q) {
return $q->where(['status >' => 0]);
},
'Orders.Agplans'
])
->matching('Users', function ($q) use($owner_id)
{
return $q->where([
'Users.owner_id' => $owner_id
]);
})
->all();
但是大多数网站都没有订单,所以我得到了一些结果:
(int) 100 => object(App\Model\Entity\Site) {
'id' => (int) 7966,
'name' => 'Site example',
'orders' => [],
'users' => [
(int) 0 => object(App\Model\Entity\User) {
...
是否可以在查询中指定我只想要 sites
而不是空 orders
?
因为你有一个 hasMany
关联,你必须采取额外的措施来包含 Orders
。
使用内部联接
您可以使用 INNER
联接,这将 select 只有那些存在匹配顺序的行。出于过滤目的,这可以使用 Query::innerJoinWith()
轻松完成,它类似于 Query::matching()
,但它不会加载任何结果。
$sites = $this->Sites
->find('all')
->select(['id', 'name'])
// ...
->innerJoinWith('Orders', function ($q) {
return $q->where(['Orders.status >' => 0]);
})
->group(['Sites.id']) // may or may not be necessary
->all();
像您一样使用匹配
您已经在使用 Query::matching()
作为 Users
,所以我假设您知道它的作用...过滤。为 Orders
添加进一步的匹配也是一种选择,但是它会获取额外的数据。
$sites = $this->Sites
->find('all')
->select(['id', 'name'])
// ...
->matching('Orders', function ($q) {
return $q->where(['Orders.status >' => 0]);
})
->group(['Sites.id']) // may or may not be necessary
->all();
最后但同样重要的是,使用计数器缓存
使用正确索引的计数器缓存可能是性能最佳的选项,因为过滤将通过同一 table 中的列完成。
您可以在 Orders
模型中使用适当的条件定义它,然后只需在查询中使用 where()
,例如
$this->addBehavior('CounterCache', [
'Sites' => [
'active_orders_count' => [
'conditions' => ['Orders.status >' => 0]
]
]
]);
$sites = $this->Sites
->find('all')
->select(['id', 'name'])
// ...
->where([
'active_orders_count >' => 0
])
->all();