Simplified. First draft was sup-optimal.
To compute all in one query:
SELECT p.id
,(100 * sum((a.price > 0)::int)) / cc.ct AS commercial
,(100 * sum((a.price = 0)::int)) / cf.ct AS free
FROM (SELECT count(*)::float AS ct FROM applications WHERE price > 0) AS cc
,(SELECT count(*)::float AS ct FROM applications WHERE price = 0) AS cf
,permissions p
LEFT JOIN applications_permissions ap ON ap.permission_id = p.id
LEFT JOIN applications a ON a.id = ap.application_id
GROUP BY 1, cc.ct, cf.ct
ORDER BY 2 DESC, 3 DESC, 1;
假设您的价格实际上是一个数字列 - 所以0
代替'0'
.
这包括permissions
没有附加的applications
根本(LEFT JOIN
).
如果可以有applications
不附加任何permissions
列表加起来不会达到 100%。
我计算总数(ct
) 一次并将其投射到float
在子查询中。剩下的计算可以用整数运算来完成,只有最后的/ ct
将数字转换为浮点数。这是最快且最精确的。
与 CTE 相同
如果您愿意接受更多新事物:尝试同样的方法CTE(通用表表达式 - 带查询) http://www.postgresql.org/docs/current/interactive/queries-with.html- 自 PostgreSQL 8.4 起可用。
它更干净,可能稍微快一点,因为我在一个 CTE 中同时计数,并且有一个更便宜的GROUP BY
- 这两者都可以通过子查询来完成:
WITH c AS (
SELECT sum((a.price > 0)::int) AS cc
,sum((a.price = 0)::int) AS cf
FROM applications
), p AS (
SELECT id
,sum((a.price > 0)::int) AS pc
,sum((a.price = 0)::int) AS pf
FROM permissions p
LEFT JOIN applications_permissions ap ON ap.permission_id = p.id
LEFT JOIN applications a ON a.id = ap.application_id
GROUP BY 1
)
SELECT p.id
,(100 * pc) / cc::float AS commercial
,(100 * pf) / cf::float AS free
FROM c, p
ORDER BY 2 DESC, 3 DESC, 1;