PostgreSQL:使用 2 级连接的 COUNT() 行 ONLY_FULL_GROUP_BY 活动
PostgreSQL: COUNT() rows using 2-level joins with ONLY_FULL_GROUP_BY active
问题
我在使用 2 级连接编写计算结果行的功能查询时遇到问题。
数据库tables
我有以下(简化)tables(正在开发的环境是 Drupal 8 btw,使用数据库服务):
nodes
table:
id
- 数字 id
title
- varchar
示例条目:
id title
1 My first article
2 My second article
3 My third article
comments
table:
cid
- 数字 id
entity_type
- varchar,被注释的实体
entity_id
- 数字 ID,包含引用
status
- 整数,0 表示未发布,1 表示已发布
comment
- 文字
示例条目:
cid entity_type entity_id status comment
1 node 1 1 foo
2 node 1 1 bar
3 comment 1 1 baz
4 node 1 0 spam/foul language/whatever
5 node 2 1 yeeeha
数据结构说明
"Nodes"可以评论。然后评论会存储在 "comments" table 中。对于每条评论,都有一个专门的行,其中包含评论的 ID、评论的实体类型(可以是 "node" 和 "comment")和评论实体的 ID。评论也可以评论 - 这些 "replies" 也存储在 "comments" table 中,因此这些条目因此包含 "comment" 作为 entity_id 和回复的评论的id。
我现在想通过单个查询获得以下结果:
id title comments
1 My first article 3
2 My second article 1
3 My third article 0
comments
应包含对给定节点的所有已发布评论和已发布回复的总和。因此,如果一个节点被直接评论了两次,并且其中一条评论也被评论了,那么 comments
计数应该是 3
。 (注意:atm"replies"的评论无法回复,所以这里只有3级环境(node
< comment
< comment
))。
正在使用的数据库:
正在使用的数据库是 PostgreSQL 9.6,ONLY_FULL_GROUP_BY
处于活动状态。
我试过的
我现在已经花了几个小时尝试查询数据,这些查询几乎都类似于以下内容(使用 Drupal 的数据库服务 select
接口):
SELECT n.id, n.title, COUNT(c.cid)+COUNTr.cid) AS comments
FROM nodes n
LEFT JOIN comments c
ON c.type = "node" AND n.id = c.entity_id AND c.status = 1
LEFT JOIN comments r
ON r.type = "comment" AND c.id = r.entity_id AND r.status = 1
GROUP BY n.id, n.title, c.entity_id, r.entity_id
但对于我来说,我就是想不出编写查询的正确方法。我的基本思路是select基础table节点,左加入第一阶段的评论,然后再次左加入对第一阶段的回复。但似乎我的数据库对我的查询有其他想法......¯\_(ツ)_/¯
我真的希望有人能让我回到正轨。任何帮助是极大的赞赏!感谢您花时间阅读所有这些内容。
你的逻辑很好。您只需要在第一级计算不同的值,并正确处理 NULL
值。此外,您希望对来自 nodes
的列进行分组,而不是来自 comments
.
select
n.id,
n.title,
coalesce(count(distinct c1.cid), 0) + coalesce(count(c2.cid), 0) "comments"
from nodes n
left join comments c1
on c1.entity_id = n.id
and c1.entity_type = 'node'
and c1.status = 1
left join comments c2
on c2.entity_id = c1.cid
and c2.entity_type = 'comment'
and c2.status = 1
group by n.id, n.title
此 demo on DB Fiddle 与您的示例数据 returns:
| id | title | comments |
| --- | ----------------- | -------- |
| 1 | My first article | 3 |
| 2 | My second article | 1 |
| 3 | My third article | 0 |
首先,让我们了解您写了什么和错过了什么 - 在查询中,您错过了 ( 在第一行的计数之后。
其次,您使用额外的 "r.entity_id" 进行分组,这不是必需的,它会隔离结果。
结果按节点 ID 升序排列。
如果对您有帮助,请使用以下查询并标记正确答案。
SELECT n.id, n.title, COUNT(c.cid)+COUNT(r.cid) AS comments
FROM nodes n
left JOIN comments c
ON c.entity_type = 'node' AND n.id = c.entity_id AND c.status = 1
left JOIN comments r
ON r.entity_type = 'comment' AND c.cid = r.entity_id AND r.status = 1
GROUP BY n.id, n.title, c.entity_id
order by n.id asc
问题
我在使用 2 级连接编写计算结果行的功能查询时遇到问题。
数据库tables
我有以下(简化)tables(正在开发的环境是 Drupal 8 btw,使用数据库服务):
nodes
table:
id
- 数字 id
title
- varchar
示例条目:
id title
1 My first article
2 My second article
3 My third article
comments
table:
cid
- 数字 id
entity_type
- varchar,被注释的实体
entity_id
- 数字 ID,包含引用
status
- 整数,0 表示未发布,1 表示已发布
comment
- 文字
示例条目:
cid entity_type entity_id status comment
1 node 1 1 foo
2 node 1 1 bar
3 comment 1 1 baz
4 node 1 0 spam/foul language/whatever
5 node 2 1 yeeeha
数据结构说明
"Nodes"可以评论。然后评论会存储在 "comments" table 中。对于每条评论,都有一个专门的行,其中包含评论的 ID、评论的实体类型(可以是 "node" 和 "comment")和评论实体的 ID。评论也可以评论 - 这些 "replies" 也存储在 "comments" table 中,因此这些条目因此包含 "comment" 作为 entity_id 和回复的评论的id。
我现在想通过单个查询获得以下结果:
id title comments
1 My first article 3
2 My second article 1
3 My third article 0
comments
应包含对给定节点的所有已发布评论和已发布回复的总和。因此,如果一个节点被直接评论了两次,并且其中一条评论也被评论了,那么 comments
计数应该是 3
。 (注意:atm"replies"的评论无法回复,所以这里只有3级环境(node
< comment
< comment
))。
正在使用的数据库:
正在使用的数据库是 PostgreSQL 9.6,ONLY_FULL_GROUP_BY
处于活动状态。
我试过的
我现在已经花了几个小时尝试查询数据,这些查询几乎都类似于以下内容(使用 Drupal 的数据库服务 select
接口):
SELECT n.id, n.title, COUNT(c.cid)+COUNTr.cid) AS comments
FROM nodes n
LEFT JOIN comments c
ON c.type = "node" AND n.id = c.entity_id AND c.status = 1
LEFT JOIN comments r
ON r.type = "comment" AND c.id = r.entity_id AND r.status = 1
GROUP BY n.id, n.title, c.entity_id, r.entity_id
但对于我来说,我就是想不出编写查询的正确方法。我的基本思路是select基础table节点,左加入第一阶段的评论,然后再次左加入对第一阶段的回复。但似乎我的数据库对我的查询有其他想法......¯\_(ツ)_/¯
我真的希望有人能让我回到正轨。任何帮助是极大的赞赏!感谢您花时间阅读所有这些内容。
你的逻辑很好。您只需要在第一级计算不同的值,并正确处理 NULL
值。此外,您希望对来自 nodes
的列进行分组,而不是来自 comments
.
select
n.id,
n.title,
coalesce(count(distinct c1.cid), 0) + coalesce(count(c2.cid), 0) "comments"
from nodes n
left join comments c1
on c1.entity_id = n.id
and c1.entity_type = 'node'
and c1.status = 1
left join comments c2
on c2.entity_id = c1.cid
and c2.entity_type = 'comment'
and c2.status = 1
group by n.id, n.title
此 demo on DB Fiddle 与您的示例数据 returns:
| id | title | comments |
| --- | ----------------- | -------- |
| 1 | My first article | 3 |
| 2 | My second article | 1 |
| 3 | My third article | 0 |
首先,让我们了解您写了什么和错过了什么 - 在查询中,您错过了 ( 在第一行的计数之后。
其次,您使用额外的 "r.entity_id" 进行分组,这不是必需的,它会隔离结果。
结果按节点 ID 升序排列。
如果对您有帮助,请使用以下查询并标记正确答案。
SELECT n.id, n.title, COUNT(c.cid)+COUNT(r.cid) AS comments
FROM nodes n
left JOIN comments c
ON c.entity_type = 'node' AND n.id = c.entity_id AND c.status = 1
left JOIN comments r
ON r.entity_type = 'comment' AND c.cid = r.entity_id AND r.status = 1
GROUP BY n.id, n.title, c.entity_id
order by n.id asc