我有两张桌子。1-“cpv”;2-“俱乐部优惠”。
在“cpv”表中,我存储了cpv代码、它们的id和名称。您可以看到CPV代码here。有6个级别的CPV代码,可以通过访问提供的链接看到。
在CPV表中有字段:“id”和“name”。
下面是一些一级cpv的示例(我们可以称它们为根cpv):
编号:03000000
名称:农、农、渔、林及相关产品
编号:09000000
名称:石油产品、燃料、电力和其他能源
共有45个根cpv,他们有自己的孩子。从我提供给您的链接可以看出,他们的id的层次结构非常严格。例如,根CPV 03000000具有二级子级:
03100000:农业和园艺产品
谷物、土豆、蔬菜、水果和坚果
农猎渔产品
03400000:林业和伐木产品
现在,对于每个CPV,都有公司在该领域开展业务(公司为该领域提供报价),例如
03100000:农业和园艺产品
很少有公司的业务是创造食品,这就是为什么他们与这家cpv有联系。这些公司的报价存储在不同的“公司报价”表中,但现在这并不重要。重要的是,有一个表“company_offer_cpv”连接company_offer和cpv表。
“公司报价”表有以下字段:
“id”,“公司报价id”,“cpv id”。这就是我如何将公司与其领域的cpv代码连接起来的方法,因为它们可以有许多代码分配给它们。
我要做的是计算每个cpv组的company_offer_cpv表中使用的所有cpv,并在group(当我说group I是指根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名称,以便在count numbers旁边显示它们:
$Cpv name=Cpv::find()->选择('name')->其中(['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急切加载,我不会得到任何结果,因为我需要从我的公司提供的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 Sama!
以下是完整的解决方案:
$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>";
}

最佳答案

我不熟悉Yii,但根据文档,您可以尝试以下操作:

$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();

或者,您可以对第二个查询使用WHERE IN()语句,因为使用紧急加载的想法是相同的:
$ids = array();
foreach ($total as $data)
{
    $id[] = $data->cpv_id."000000";
}

然后:
// I'm not sure about WhereIn() Yii stuff :)
$cpvNames = Cpv::find()->select('name, id')->where(['id' => $ids])->all();
// Create an associative array, not sure how it's done with Yii
$cpvNames = CHtml::listData( $cpvNames, 'id' , 'name');

最后:
foreach ($total as $data) {

    $id = $data->cpv_id."000000";
    echo $cpvNames[$id]. " " . $data->count;
    echo "<br>";
}

扼要重述:
您将只得到两个查询:
SELECT LEFT(cpv_id, 2) AS cpv_id, COUNT(cpv_id) AS count FROM `club_offer_cpv` GROUP BY LEFT(cpv_id, 2)

第二个用where in代替equal
SELECT `name` FROM `cpv` WHERE `id` in ('50000000', 800000, ...)

10-07 17:05