Laravel5:复杂的 hasManyThrouh 自引用关系(带有别名和 SQL 计算)
Laravel5: Complex hasManyThrouh self referencing relation (with aliases and SQL calculations)
我正在 laravel 重建一个项目,我当前的问题是定义一个复杂的自引用 hasManyThrough 关系与 table 别名和 SQL 计算。
该关系应该根据匹配标签的向下总和来查找相关商家。模型拥有的相同标签越多,它们就越相关。
到目前为止,还不错。在我的旧项目中,我只是写下了以下 suitable SQL 查询:
SELECT source_merchant.id, target_merchant.id, COUNT(target_merchant.id) /
((
(SELECT COUNT(*) FROM tagged WHERE model = 'Merchant' AND model_id = source_merchant.id) +
(SELECT COUNT(*) FROM tagged WHERE model = 'Merchant' AND model_id = target_merchant.id)
) /2 ) as similarity
FROM merchants source_merchant
LEFT JOIN tagged source_merchant_tags ON (
source_merchant.id = source_merchant_tags.model_id AND
source_merchant_tags.model = 'Merchant'
)
INNER JOIN tagged target_merchant_tags ON (
source_merchant_tags.tag_id = target_merchant_tags.tag_id
AND (source_merchant_tags.model = 'Merchant' AND target_merchant_tags.model = 'Merchant')
AND (source_merchant_tags.model_id != target_merchant_tags.model_id)
)
LEFT JOIN merchants target_merchant ON (
target_merchant_tags.model_id = target_merchant.id AND target_merchant_tags.model = 'Merchant'
)
WHERE source_merchant.id = 2
GROUP BY source_merchant.id, target_merchant.id
ORDER BY similarity DESC
LIMIT 5
最好是捕捉类似
的东西
public function related_merchants() {
return $this->hasManyThroug(relations_stuff_i_cannot_imagine...)
->selectRaw("SELECT source_merchant.id, target_merchant.id, COUNT(target_merchant.id) /
((
(SELECT COUNT(*) FROM tagged WHERE model = 'Merchant' AND model_id = source_merchant.id) +
(SELECT COUNT(*) FROM tagged WHERE model = 'Merchant' AND model_id = target_merchant.id)
) /2 ) as similarity")
->groupBy('source_merchant.id', 'target_merchant.id ')
->orderBy('similarity')
->limit(5);
}
就是这样 :-) 不幸的是,我找不到解决方案,因为我不知道如何在 hasManyThrough()
...
中定义 suitable 关系参数
编辑 - 尝试将 Laravel 查询构建为 :
public function getRelatedMerchantsAttribute() {
return $this->from('merchants AS source_merchant')
->selectRaw('source_merchant.id, target_merchant.id, COUNT(target_merchant.id) /
((
(' . DB::table('tagged')->whereRaw("model = 'Merchant' AND model_id = source_merchant.id")->count() . ') +
' . DB::table('tagged')->whereRaw("model = 'Merchant' AND model_id = target_merchant.id")->count() . ')
/2 ) AS similarity')
->lefJoin('tagged AS source_merchant_tags', function ($join) {
$join->on('source_merchant.id', '=', 'source_merchant_tags.model_id')
->on('source_merchant_tags.model', '=', 'Merchant');
})
->join('tagged AS target_merchant_tags', function ($join) {
$join->on('source_merchant_tags.tag_id', '=', 'target_merchant_tags.tag_id')
->on('source_merchant_tags.model', '=', 'Merchant')
->on('target_merchant_tags.model', '=', 'Merchant')
->on('source_merchant_tags.model_id', '!=', 'target_merchant_tags.model_id');
})
->leftJoin('merchants AS target_merchant', function ($join) {
$join->on('target_merchant_tags.model_id ', '=', 'target_merchant.id')
->on('target_merchant_tags.model', '=', 'Merchant');
})
->whereRaw('source_merchant.id = ?', [ $this->id ])
->groupBy('source_merchant.id', 'target_merchant.id ')
->orderBy('similarity')
->limit(5)
->get();
}
由于以下原因,此解决方案尚未生效:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'merchants.id'
in 'where clause' (SQL: select count(*) as aggregate from `tagged`
where model = 'Merchant' AND model_id = merchants.id)
Edit - 使用 会产生以下 Laravel 错误:
SQLSTATE[HY093]: 参数号无效。 SQL:
select source_merchant.id, target_merchant.id,
COUNT(target_merchant.id) /
((
(select COUNT(*) from `tagged` where `model` = Merchant and `model_id` = source_merchant.id) +
(select COUNT(*) from `tagged` where `model` = Merchant and `model_id` = target_merchant.id)
) /2 ) AS similarity
from `merchants` as `source_merchant`
left join `tagged` as `source_merchant_tags` on
`source_merchant`.`id` = `source_merchant_tags`.`model_id`
and `source_merchant_tags`.`model` = Merchant
inner join `tagged` as `target_merchant_tags` on
`source_merchant_tags`.`tag_id` = `target_merchant_tags`.`tag_id`
and `source_merchant_tags`.`model` = Merchant
and `target_merchant_tags`.`model` = 2
and `source_merchant_tags`.`model_id` != `target_merchant_tags`.`model_id`
left join `merchants` as `target_merchant` on
`target_merchant_tags`.`model_id` = `target_merchant`.`id`
and `target_merchant_tags`.`model` = ?
where `source_merchant`.`id` = ?
group by `source_merchant`.`id`, `target_merchant`.`id`
order by `similarity` desc
limit 5
我什至想知道为什么这里使用当前模型 ID:and target_merchant_tags.model = 2
...
看看这张截图。条件参数 'Merchant' 成为当前模型 ID,在本例中为 2(选定文本)。红色圆圈中的两个参数保持为空。这里有什么问题?
我认为恋爱关系不是适合您情况的正确选择。源商户和目标商户在 Laravel/Eloquent 意义上并不真正 相关,因为公共标签仅用于确定订单。
我只是将您的原始 SQL 转换为 Laravel 查询并将您的方法重命名为 getRelatedMerchantsAttribute
。然后您可以使用 $merchant->relatedMerchants
.
访问它们
试试这个查询:
$sourceCount = DB::table('tagged')
->selectRaw('COUNT(*)')
->where('model', 'Merchant')
->where('model_id', DB::raw('source_merchant.id'));
$targetCount = DB::table('tagged')
->selectRaw('COUNT(*)')
->where('model', 'Merchant')
->where('model_id', DB::raw('target_merchant.id'));
$this->from('merchants AS source_merchant')
->addBinding($sourceCount->getBindings(), 'select')
->addBinding($targetCount->getBindings(), 'select')
->selectRaw('source_merchant.id, target_merchant.id, COUNT(target_merchant.id) /
((
(' . $sourceCount->toSql() . ') +
(' . $targetCount->toSql() . '))
/2 ) AS similarity')
->leftJoin('tagged AS source_merchant_tags', function ($join) {
$join->on('source_merchant.id', '=', 'source_merchant_tags.model_id')
->where('source_merchant_tags.model', '=', 'Merchant');
})
->join('tagged AS target_merchant_tags', function ($join) {
$join->on('source_merchant_tags.tag_id', '=', 'target_merchant_tags.tag_id')
->where('source_merchant_tags.model', '=', 'Merchant')
->where('target_merchant_tags.model', '=', 'Merchant')
->on('source_merchant_tags.model_id', '!=', 'target_merchant_tags.model_id');
})
->leftJoin('merchants AS target_merchant', function ($join) {
$join->on('target_merchant_tags.model_id', '=', 'target_merchant.id')
->where('target_merchant_tags.model', '=', 'Merchant');
})
->where('source_merchant.id', $this->id)
->groupBy('source_merchant.id', 'target_merchant.id')
->orderByDesc('similarity')
->limit(5)
->get();
我正在 laravel 重建一个项目,我当前的问题是定义一个复杂的自引用 hasManyThrough 关系与 table 别名和 SQL 计算。
该关系应该根据匹配标签的向下总和来查找相关商家。模型拥有的相同标签越多,它们就越相关。
到目前为止,还不错。在我的旧项目中,我只是写下了以下 suitable SQL 查询:
SELECT source_merchant.id, target_merchant.id, COUNT(target_merchant.id) /
((
(SELECT COUNT(*) FROM tagged WHERE model = 'Merchant' AND model_id = source_merchant.id) +
(SELECT COUNT(*) FROM tagged WHERE model = 'Merchant' AND model_id = target_merchant.id)
) /2 ) as similarity
FROM merchants source_merchant
LEFT JOIN tagged source_merchant_tags ON (
source_merchant.id = source_merchant_tags.model_id AND
source_merchant_tags.model = 'Merchant'
)
INNER JOIN tagged target_merchant_tags ON (
source_merchant_tags.tag_id = target_merchant_tags.tag_id
AND (source_merchant_tags.model = 'Merchant' AND target_merchant_tags.model = 'Merchant')
AND (source_merchant_tags.model_id != target_merchant_tags.model_id)
)
LEFT JOIN merchants target_merchant ON (
target_merchant_tags.model_id = target_merchant.id AND target_merchant_tags.model = 'Merchant'
)
WHERE source_merchant.id = 2
GROUP BY source_merchant.id, target_merchant.id
ORDER BY similarity DESC
LIMIT 5
最好是捕捉类似
的东西public function related_merchants() {
return $this->hasManyThroug(relations_stuff_i_cannot_imagine...)
->selectRaw("SELECT source_merchant.id, target_merchant.id, COUNT(target_merchant.id) /
((
(SELECT COUNT(*) FROM tagged WHERE model = 'Merchant' AND model_id = source_merchant.id) +
(SELECT COUNT(*) FROM tagged WHERE model = 'Merchant' AND model_id = target_merchant.id)
) /2 ) as similarity")
->groupBy('source_merchant.id', 'target_merchant.id ')
->orderBy('similarity')
->limit(5);
}
就是这样 :-) 不幸的是,我找不到解决方案,因为我不知道如何在 hasManyThrough()
...
编辑 - 尝试将 Laravel 查询构建为
public function getRelatedMerchantsAttribute() {
return $this->from('merchants AS source_merchant')
->selectRaw('source_merchant.id, target_merchant.id, COUNT(target_merchant.id) /
((
(' . DB::table('tagged')->whereRaw("model = 'Merchant' AND model_id = source_merchant.id")->count() . ') +
' . DB::table('tagged')->whereRaw("model = 'Merchant' AND model_id = target_merchant.id")->count() . ')
/2 ) AS similarity')
->lefJoin('tagged AS source_merchant_tags', function ($join) {
$join->on('source_merchant.id', '=', 'source_merchant_tags.model_id')
->on('source_merchant_tags.model', '=', 'Merchant');
})
->join('tagged AS target_merchant_tags', function ($join) {
$join->on('source_merchant_tags.tag_id', '=', 'target_merchant_tags.tag_id')
->on('source_merchant_tags.model', '=', 'Merchant')
->on('target_merchant_tags.model', '=', 'Merchant')
->on('source_merchant_tags.model_id', '!=', 'target_merchant_tags.model_id');
})
->leftJoin('merchants AS target_merchant', function ($join) {
$join->on('target_merchant_tags.model_id ', '=', 'target_merchant.id')
->on('target_merchant_tags.model', '=', 'Merchant');
})
->whereRaw('source_merchant.id = ?', [ $this->id ])
->groupBy('source_merchant.id', 'target_merchant.id ')
->orderBy('similarity')
->limit(5)
->get();
}
由于以下原因,此解决方案尚未生效:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'merchants.id'
in 'where clause' (SQL: select count(*) as aggregate from `tagged`
where model = 'Merchant' AND model_id = merchants.id)
Edit - 使用
SQLSTATE[HY093]: 参数号无效。 SQL:
select source_merchant.id, target_merchant.id,
COUNT(target_merchant.id) /
((
(select COUNT(*) from `tagged` where `model` = Merchant and `model_id` = source_merchant.id) +
(select COUNT(*) from `tagged` where `model` = Merchant and `model_id` = target_merchant.id)
) /2 ) AS similarity
from `merchants` as `source_merchant`
left join `tagged` as `source_merchant_tags` on
`source_merchant`.`id` = `source_merchant_tags`.`model_id`
and `source_merchant_tags`.`model` = Merchant
inner join `tagged` as `target_merchant_tags` on
`source_merchant_tags`.`tag_id` = `target_merchant_tags`.`tag_id`
and `source_merchant_tags`.`model` = Merchant
and `target_merchant_tags`.`model` = 2
and `source_merchant_tags`.`model_id` != `target_merchant_tags`.`model_id`
left join `merchants` as `target_merchant` on
`target_merchant_tags`.`model_id` = `target_merchant`.`id`
and `target_merchant_tags`.`model` = ?
where `source_merchant`.`id` = ?
group by `source_merchant`.`id`, `target_merchant`.`id`
order by `similarity` desc
limit 5
我什至想知道为什么这里使用当前模型 ID:and target_merchant_tags.model = 2
...
看看这张截图。条件参数 'Merchant' 成为当前模型 ID,在本例中为 2(选定文本)。红色圆圈中的两个参数保持为空。这里有什么问题?
我认为恋爱关系不是适合您情况的正确选择。源商户和目标商户在 Laravel/Eloquent 意义上并不真正 相关,因为公共标签仅用于确定订单。
我只是将您的原始 SQL 转换为 Laravel 查询并将您的方法重命名为 getRelatedMerchantsAttribute
。然后您可以使用 $merchant->relatedMerchants
.
试试这个查询:
$sourceCount = DB::table('tagged')
->selectRaw('COUNT(*)')
->where('model', 'Merchant')
->where('model_id', DB::raw('source_merchant.id'));
$targetCount = DB::table('tagged')
->selectRaw('COUNT(*)')
->where('model', 'Merchant')
->where('model_id', DB::raw('target_merchant.id'));
$this->from('merchants AS source_merchant')
->addBinding($sourceCount->getBindings(), 'select')
->addBinding($targetCount->getBindings(), 'select')
->selectRaw('source_merchant.id, target_merchant.id, COUNT(target_merchant.id) /
((
(' . $sourceCount->toSql() . ') +
(' . $targetCount->toSql() . '))
/2 ) AS similarity')
->leftJoin('tagged AS source_merchant_tags', function ($join) {
$join->on('source_merchant.id', '=', 'source_merchant_tags.model_id')
->where('source_merchant_tags.model', '=', 'Merchant');
})
->join('tagged AS target_merchant_tags', function ($join) {
$join->on('source_merchant_tags.tag_id', '=', 'target_merchant_tags.tag_id')
->where('source_merchant_tags.model', '=', 'Merchant')
->where('target_merchant_tags.model', '=', 'Merchant')
->on('source_merchant_tags.model_id', '!=', 'target_merchant_tags.model_id');
})
->leftJoin('merchants AS target_merchant', function ($join) {
$join->on('target_merchant_tags.model_id', '=', 'target_merchant.id')
->where('target_merchant_tags.model', '=', 'Merchant');
})
->where('source_merchant.id', $this->id)
->groupBy('source_merchant.id', 'target_merchant.id')
->orderByDesc('similarity')
->limit(5)
->get();