如何解决您如何使用PostgreSQL将多个结果分组到一个列中,并对每个结果进行计数
我现在正处于挣扎中,我整天都在找东西,但是我没有设法找出应该做的事情。
我想使用postgres查看我的API(如果需要,可以是一个函数) 这将显示出少数顶级玩家(创造最多赛事的玩家)
我正在寻找的结果将是这样的输出:
class Export < ApplicationRecord
has_one_attached :item
def process_pdf!
pdf_file_name = "#{item.blob.key}_#{item.blob.filename.to_s}"
xls_file_name = "#{item.blob.key}_#{item.blob.filename.to_s.sub('pdf','')}"
file = "#{Rails.root}/tmp/#{pdf_file_name}"
File.open(file,'wb') do |f|
f.write(pdf.download)
end
PdfScraper.call(pdf_file: file,output_name: xls_file_name)
self.item.attach(
io: File.open("#{Rails.root}/tmp/#{xls_file_name}"),filename: "#{xls_file_name}.xlsx",content_type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
File.delete(file)
true
end
end
首先,我有这样的事件表
{"nickname": "Username",...,"total_event_created": 12,"Events":{"eventID": 1,"event_name":CS:go,"total": 6},{"eventID: 2,"event_name": lol,"total": 6}
我使用CREATE TABLE "event" (
"id" INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,"user_id" INT NOT NULL REFERENCES "user"("id"),"game_id" INT NOT NULL REFERENCES "game"("id"),"event_time" TIMESTAMPTZ NOT NULL,"duration" INTERVAL,"player_count" INT NOT NULL DEFAULT 1 CONSTRAINT max_player CHECK (player_count <= player_max),"player_max" INT NOT NULL,"description" TEXT,"status" INT NOT NULL DEFAULT 0,"vocal" TEXT);
尝试了很多不同的方法,但是我从来没有设法解决问题。
到目前为止,我最好的尝试是这样:
json_agg()
输出:
SELECT DISTINCT ON (e.user_id) "user_id" AS "_user_id",us.nickname AS "_name",us.avatar AS "_avatar",us.banner AS "_banner",(SELECT COUNT(id) FROM user_access."event" ev WHERE us.id = ev.user_id) AS "_total_events",(SELECT COUNT (CASE WHEN g.id = 1 THEN 1 END) ) AS "_total_cs",(SELECT COUNT (CASE WHEN g.id = 2 THEN 1 END) ) AS "_total_lol"
FROM user_access."user" us
JOIN user_access."event" e ON us.id = e.user_id
JOIN user_access."game" g ON e.game_id = g.id
GROUP BY e.user_id,us.nickname,us.id ;
感谢家伙清除了我的代码,从您寄给我的信息来看,我得到了一些更好的信息:
_user_id | _name | _avatar | _banner | _total_events | _total_cs | _total_lol
----------+------------+-------------+-------------+---------------+-----------+------------
1 | test1login | avatar1.png | banner1.png | 3 | 2 | 1
2 | test2login | avatar2.png | banner2.png | 1 | 0 | 1
输出:
SELECT us."id" AS "_user_id",COUNT(DISTINCT e.id) as "_total_events",jsonb_build_object('cs',COUNT(*) FILTER (WHERE g.id = 1 ),'lol',COUNT(*) FILTER (WHERE g.id = 2)) AS "_total_by_game"
FROM user_access."user" us
JOIN user_access."event" e ON us.id = e.user_id
JOIN user_access."game" g ON e.game_id = g.id
GROUP BY us.id
ORDER BY "_total_events" DESC;
解决方法
您可以使用条件聚合:
SELECT us."user_id" AS "_user_id",us.nickname AS "_name",us.avatar AS "_avatar",us.banner AS "_banner",COUNT(DISTINCT e.id) as "_total_events",COUNT(*) FILTER (WHERE g.id = 1 ) AS "_total_cs",COUNT(*) FILTER (WHERE g.id = 2) AS "_total_lol"
FROM user_access."user" us JOIN
user_access."event" e
ON us.id = e.user_id JOIN
user_access."game" g
ON e.game_id = g.id
GROUP BY us.id ;
,
查询中有几个问题:
- 您按用户分组。您可以进行三次此操作,但没有明显的原因:一次按他们的ID,然后按他们的名字,再按一次ID。
- 您使用
DISTINCT ON
用户ID。为什么?GROUP BY
已经为每个用户提供了一行。然后,用DISTINCT ON
说:从哪一行给我一行,无论哪一个(因为对于ORDER BY
通常没有DISTINCT ON
子句,但是,您反正每位用户只有一行,所以这都是无效的。 -
(SELECT COUNT (CASE WHEN g.id = 1 THEN 1 END) )
无效,应该引发错误。可以将其重写为CASE WHEN g.id = 1 THEN 1 ELSE 0 END
。但是,当您按每个用户进行汇总时,可能会有多个g.id。您要显示哪一个?必须有一个聚合功能才能使其正常工作,例如SUM((SELECT COUNT (CASE WHEN g.id = 1 THEN 1 END)))
,当然还是SUM(CASE WHEN g.id = 1 THEN 1 ELSE 0 END)
。
似乎您只想进行汇总:
SELECT
us.id AS "_user_id",COUNT(*) AS "_total_events",COUNT(CASE WHEN g.id = 1 THEN 1 END) AS "_total_cs",COUNT(CASE WHEN g.id = 2 THEN 1 END) AS "_total_lol"
FROM user_access.user us
JOIN user_access.event e ON e.user_id = us.id
JOIN user_access.game g ON g.id = e.game_id
GROUP BY us.id
对于前5个添加:
ORDER BY COUNT(*) DESC
FETCH FIRST 5 ROWS ONLY;
顺便说一句:您是否真的想计算用户在游戏1(_total_cs)和游戏2(_total_lol)中发生了多少个事件?还是错别字?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。