【发布时间】:2015-02-12 20:13:37
【问题描述】:
我有 2 张桌子。 1 - “cpv”; 2 - “club_offer_cpv”。
在“cpv”表中,我存储了 CPV 代码、它们的 ID 和名称。您可以看到 CPV 代码here。 CPV 代码共有 6 个级别,您可以通过访问提供的链接查看。
在 CPV 表中有字段:“id”和“name”。
以下是一些一级 CPV 的示例(我们可以称它们为根 CPV):
id:03000000
名称:农、农、渔、林及相关产品
id: 09000000
名称:石油产品、燃料、电力和其他能源
有 45 个根 CPV,它们有自己的子节点。从我提供给您的链接中可以看出,他们 ID 的层次结构非常严格。例如,根 CPV 03000000 具有二级子级:
03100000 : 农产品和园艺产品
03200000 : 谷物、土豆、蔬菜、水果和坚果
03300000 : 农业、狩猎和渔业产品
03400000 : 林业和伐木产品
现在,对于每个 CPV,都有一家公司在该领域开展业务(公司正在为该领域提供报价),例如,
03100000 : 农产品和园艺产品
很少有公司的业务是创造食物,这就是他们与这个 cpv 相关联的原因。这些公司的报价存储在不同的表“company_offer”中,但这现在并不重要。重要的是有一个表“company_offer_cpv”连接 company_offer 和 cpv 表。
“company_offer_cpv”表有这些字段:
“id”、“company_offer_id”、“cpv_id”。这就是我可以将公司与其领域的 cpv 代码联系起来的方法,因为他们可以分配有许多代码。
我想做的是为每个 CPV 组计算 company_offer_cpv 表中使用的所有 CPV,并在组旁边显示这些数字(当我说组时,我的意思是 root cpv)名称。像这样:
03000000 : 农业、农业、渔业、林业及相关产品 : 240
09000000 : 石油产品、燃料、电力和其他能源 : 130
14000000:采矿、基本金属及相关产品:72
等等……
我用的是yii2 php框架,不过如果你不使用也没关系,你可以帮我用mysql/php代码。
要计算表 company_offer_cpv 中使用的所有 CPV 的数量,并按上述方式显示它们,我使用以下代码:
$total = ClubOfferCpv::find()->groupBy( ['LEFT(cpv_id, 2)'] )
->select( ['LEFT(cpv_id, 2) AS cpv_id', 'COUNT(cpv_id) AS count'])
->all();
foreach ($total as $data)
{
$id = $data->cpv_id."000000";
$cpvName = Cpv::find()->select('name')->where(['id' => $id])->one();
echo $cpvName->name. " " . $data->count;
echo "<br>";
}
但是我的代码中有一个缺陷(或更多:))。如果你看一下 foreach 循环,我正在执行这行代码来获取所有根 cpv 名称,这样我就可以在计数旁边显示它们:
$cpvName = Cpv::find()->select('name')->where(['id' => $id])->one();
由于有 45 个根 CPV,此行将导致执行 45 个查询。我需要总共进行 1 或 2 个查询,但我不知道如何。我知道 Yii2 提供了Eager Loading 但我不知道如何使用它。有谁知道我可以如何使用 yii2 或简单的 sql/php 来解决这个问题?
这是第一行代码执行的sql:
SELECT LEFT(cpv_id, 2) AS cpv_id, COUNT(cpv_id) AS count FROM `club_offer_cpv` GROUP BY LEFT(cpv_id, 2)
这是由 foreach 中的行执行的 SQL 之一:
SELECT `name` FROM `cpv` WHERE `id`='50000000'
提前谢谢你
这是为了很好地回应 JC Sama 的帮助而进行的更新:
如果我按照你所说的那样尝试使用 yii2 预加载,我不会得到任何结果,因为我需要从我的 company_offer_cpv 表中删除 cpv_id。以下是 eager 执行的查询:
SELECT LEFT(cpv_id, 2) AS cpv_id, COUNT(cpv_id) AS count FROM `club_offer_cpv` GROUP BY LEFT(cpv_id, 2) ;
第二个:
SELECT * FROM `cpv` WHERE `id` IN ('03', '09', '14', '15', '16', '18', '19', '22', '24', '30', '31', '32', '33', '34', '35', '37', '38', '39', '41', '42', '43', '44', '45', '48', '50', '51', '55', '60', '63', '64', '65', '66', '70', '71', '72', '73', '75', '76', '77', '79', '80', '85', '90', '92', '98')
非常感谢 JC 萨玛!
这里是完整的解决方案:
$total = ClubOfferCpv::find()->groupBy( ['LEFT(cpv_id, 2)'] )
->select( ['LEFT(cpv_id, 2) AS cpv', 'CONCAT(LEFT(cpv_id, 2), "000000") AS cpv_id', 'COUNT(cpv_id) AS count'])
->with('cpv')
->all();
foreach ($total as $data)
{
echo $data->cpv->name. " " . $data->count;
echo "<br>";
}
【问题讨论】:
标签: php mysql sql yii2 eager-loading