我希望使用Eloquent从我们的数据库输出一些数据,但数据库可能会有所不同。
以下是我的数据库表格的说明
网络服务标签:
----------------------------------------------------------
| id | webservice_tag | webservice_name | blog_id |
==========================================================
| 1 | TEST, TESSST, TES | Test Service | 1 |
----------------------------------------------------------
| 2 | OPTION, OPT, EXAMPLE | Example Service | 1 |
----------------------------------------------------------
| 3 | ANOTHER, ANO, THER | Another Service | 1 |
----------------------------------------------------------
博文:
----------------------------------------------------------
| id | title | blog_id | tag |
==========================================================
| 1 | Blog Title 1 | 1 | THER |
----------------------------------------------------------
| 2 | Blog Title 2 | 1 | TES |
----------------------------------------------------------
| 3 | Blog Title 3 | 1 | ANOTHER |
----------------------------------------------------------
所以在这里,我们有两个表。博客帖子和网络服务标签。
我们的博客文章中包含来自众多不同提供商的大量网络服务。例如,测试服务,示例服务和其他服务。但是,这些Web服务非常不一致;他们将通过标签组合发送,并且不保证两个帖子是相同的。
因此,我们创建了一个名为Webservice Tags的表,用于记录这些出现的每一个。通过这种方式,我们可以确定(在示例中)博客标题3是由另一个服务发送的,博客标题2是由测试服务等发送的。
我正在开发报告,以显示我们从每个网络服务获得的帖子数量。因此,对于每篇博文,我需要识别Web服务并获取与之关联的Web服务名称。我们有多个博客,每个博客都有自己的网络服务(有些可能会共享标签),因此需要将此报告与每个博客隔离开来。
这是Eloquent中的查询:
$query = DB::table('blog_posts')
->join('webservice_tags', function($join) use ($blog) {
$join->on('blog_posts.tag', '=', 'webservice_tags.webservice_tag')
->where('webservice_tags.blog_id', '=', $blog->id);
})
->addSelect('webservice_tags.webservice_name AS name')
->addSelect(DB::raw("COUNT(blog_posts.id) AS count"))
->where('blog_posts.blog_id', '=', $blog->id)
->groupBy('webservice_tags.webservice_name')
->get();
此查询很好,而Webservice发送了一致的标记。但是现在每个Web服务都有不同的标记,而且这个报告需要平均计算它们。
这是我的修正案,但它没有按预期运作:
->join('webservice_tags', function($join) use ($blog) {
$join->on('blog_posts.tag', 'LIKE', DB::raw('CONCAT("%", webservice_tags.webservice_tag, "%")'))
->where('webservice_tags.blog_id', '=', $blog->id);
})
我没有通过此方法在查询中获得任何匹配。
该查询旨在将任何字段连接到SELECT,其中blog_posts.tag位于逗号分隔的webservice_tags列表中。
有没有办法更有效地做到这一点?
关于blog_id
关系的解释
此系统管理多个博客以及这些博客中的帖子。 Web服务可能适用于一个博客,但不适用于另一个博客,这就是blog_id
与webservices以及各个帖子相关联的原因。有一些事项,比如与Web服务相关的佣金百分比,Test Webservice可能为博客A提供10%,为博客B提供12%,因此它们基本上是分开的。
答案 0 :(得分:1)
您没有看到任何结果的原因是:
$join->on('blog_posts.tag', 'LIKE', DB::raw('CONCAT("%", webservice_tags.webservice_tag, "%")'))
转换为:
INNER JOIN `webservice_tags`
ON `blog_posts`.`tag` LIKE CONCAT("%", webservice_tags.webservice_tag, "%")
这会尝试匹配blog_posts
的值tag
。%ANOTHER, ANO, THER%
。
所以,让我们说blog_posts.tag
是"另一个"而webservice_tags.webservice_tag
是"另一个,另一个,那个"。数据库正在尝试匹配以下值:
ANOTHER != FOOANOTHER, ANO, THER
ANOTHER != ANOTHER, ANO, THERBAR
ANOTHER != FOOANOTHER, ANO, THERBAR
这就是为什么你没有得到任何结果的原因。您将需要交换列,如下所示:
$join->on('webservice_tags.webservice_tag', 'LIKE', DB::raw('CONCAT("%", blog_posts.tag, "%")'))
我要在这里抛出我的想法。在考虑这个问题时,我会想到以下几点:
blog_id
列,因为我还不太清楚他们做了什么。首先,我首先尝试将表格首先规范化为webservices,webservice_tags,tags和blog_posts,如下所示:
<强> web服务:强>
-------------------------
| id | webservice_name |
=========================
| 1 | Test Service |
-------------------------
| 2 | Example Service |
-------------------------
| 3 | Another Service |
-------------------------
<强> webservice_tags:强>
------------------------------------------
| id | tag_name | webservice_id |
==========================================
| 1 | TEST | 1 |
------------------------------------------
| 2 | TESSST | 1 |
------------------------------------------
| 3 | TES | 1 |
------------------------------------------
| 4 | OPTION | 2 |
------------------------------------------
| 5 | OPT | 2 |
------------------------------------------
| 6 | EXAMPLE | 2 |
------------------------------------------
| 7 | ANOTHER | 3 |
------------------------------------------
| 8 | ANO | 3 |
------------------------------------------
| 9 | THER | 3 |
------------------------------------------
| 10 | FOO | NULL |
------------------------------------------
| 11 | BAR | NULL |
------------------------------------------
请注意,为了便于阅读,我在上面的数据透视表中使用tag_name
。我想最好使用tag_id
代替。
<强>标签:强>
--------------------------
| id | tag_name |
==========================
| 1 | TEST |
--------------------------
| 2 | TESSST |
--------------------------
| 3 | TES |
--------------------------
| 4 | OPTION |
--------------------------
| 5 | OPT |
--------------------------
| 6 | EXAMPLE |
--------------------------
| 7 | ANOTHER |
--------------------------
| 8 | ANO |
--------------------------
| 9 | THER |
--------------------------
| 10 | FOO |
--------------------------
| 11 | BAR |
--------------------------
<强> blog_posts:强>
-----------------------------------------------------------
| id | title | blog_id | tag_name |
===========================================================
| 1 | Blog Title 1 | 1 | THER |
-----------------------------------------------------------
| 2 | Blog Title 2 | 1 | TES |
-----------------------------------------------------------
| 3 | Blog Title 3 | 1 | ANOTHER |
-----------------------------------------------------------
现在,要获取每个Web服务创建的博客帖子的报告,我们可以使用联接查询来执行此操作。 在这种情况下,QueryBuilder查询会提供更好的性能,因为我们只想知道聚合,而不是实际的数据库模型:
$report = DB::table('webservices')
->leftJoin('webservice_tags', 'webservice_tags.webservice_id', '=', 'webservices.id')
->leftJoin('tags', 'tags.tag_name', '=', 'webservices_tags.tag_name')
->leftJoin('blog_posts', 'blog_posts.tag_name', '=', 'tags.tag_name')
->where('blog_posts.blog_id', '=', $blog->id)
->select(['webservices.webservice_name', DB::raw('COUNT(`blog_posts.id`) as `num_posts`')])
->groupBy('webservices.id')
->get();
现在,您可以获得每个Web服务为所有Web服务创建的博客帖子的报告。
一个注意事项是,由于您提到某个网络服务可能会共享代码,而您正在识别网络服务&lt; - &gt;博客文章通过标签, 您无法100%准确地确定原始网络服务,因为您无法确定哪个网站服务为该帖子设置了该标记。
额外:您可能会注意到我还在Web服务标签中添加了FOO和BAR。 这有助于万一,就像你说的那样,Web服务非常不一致&#34;,新的标签将被添加到你的数据库中。 您还可以查询它们并轻松生成报告,以找出尚未映射的标记。