我有三个表:application,permissions和applications_permissions
|------------| |------------------------| |-----------|
|applications| |applications_permissions| |permissions|
|------------| |------------------------| |-----------|
| id | <-| application_id | | id |
| price | | permission_id |-> | name |
|------------| |------------------------| |-----------|
对于应用程序,有两类:免费和商业(价格='0'和价格!='0')
现在我想知道每个权限,总应用程序中有多少百分比引用它;这两个类别
免:
id, percentage
1 , 20.0230
2 , 0.0000
3 , 0.0312
...
商业:
id, percentage
1 , 18.0460
2 , 0.0000
3 , 0.0402
...
我已经计算出以下查询,但它不包含没有应用程序的权限ID:/
SELECT (SELECT name FROM permissions WHERE id = applications_permissions.permission_id) AS "name",
100::float * COUNT(*)/(SELECT COUNT(name) FROM applications WHERE price = \'0\') AS "percent"
FROM applications, applications_permissions
WHERE applications.id = applications_permissions.application_id
AND applications.price = \'0\'
GROUP BY applications_permissions.permission_id
ORDER BY percent DESC')
我该怎么做? 我现在已经尝试了几个小时(那个查询,misc JOINs)但它让我望而却步:/
答案 0 :(得分:4)
简化。初稿是最优的。
要在一个查询中计算所有内容:
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
没有附加到任何ct
,那么这些列表的累计不会达到100%。
我执行总计数(float
)一次并将其转换为子查询中的/ ct
。其余的计算可以使用整数运算来完成,只有最后的GROUP BY
将数字转换为浮点数。这是最快和最精确的。
如果您对更多新内容持开放态度:请尝试使用CTEs (Common Table Expressions - WITH queries) - 从PostgreSQL 8.4开始提供。
它更干净,可能稍微快一些,因为我在一个CTE中都做了两个并且有更便宜的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;
- 这两个都可以用子查询来完成:
{{1}}
答案 1 :(得分:3)
使用LEFT OUTER JOIN
:
SELECT * FROM permissions LEFT OUTER JOIN
applications_permissions as rel on permissions.id = rel.permission_id LEFT OUTER JOIN
applications on rel.application_id = applications.id
答案 2 :(得分:1)
这有用吗?
对于free
案例:
SELECT p.id, (100::float * COUNT(p.id)/(SELECT COUNT(*) from Applications)) Percent
FROM Applications a, Permissions p, Applications_Permissions a_p
WHERE a.id = a_p.application_id AND p.id = a_p.permission_id AND a.price = 0
GROUP BY p.id
ORDER BY Percent DESC
答案 3 :(得分:1)
以下是一个查询中的结果:
SELECT p.id
, p.name
, (CASE WHEN total.free=0 THEN NULL ELSE 100::float * sub.free::float / total.free::float END) AS percent_free
, (CASE WHEN total.comm=0 THEN NULL ELSE 100::float * sub.comm::float / total.comm::float END) AS percent_comm
FROM permissions AS p
LEFT JOIN (
SELECT permission_id
, SUM(CASE WHEN a.price<=0 THEN 1 ELSE 0 END) AS free
, SUM(CASE WHEN a.price>0 THEN 1 ELSE 0 END) AS comm
FROM applications_permissions AS pa
JOIN applications AS a ON (pa.application_id=a.id)
GROUP BY permission_id
) AS sub ON (p.id=sub.permission_id)
, (
SELECT
SUM(CASE WHEN price<=0 THEN 1 ELSE 0 END) AS free
, SUM(CASE WHEN price>0 THEN 1 ELSE 0 END) AS comm
FROM applications
) AS total
或仅对免费应用程序(通过更改where子句分别为商业应用程序)的结果:
SELECT p.id
, p.name
, (CASE WHEN total.nbr=0 THEN NULL ELSE 100::float * sub.nbr::float / total.nbr::float END) AS percent
FROM permissions AS p
LEFT JOIN (
SELECT permission_id, COUNT(*) AS nbr
FROM applications_permissions AS pa
JOIN applications AS a ON (pa.application_id=a.id)
WHERE (a.price<=0)
GROUP BY permission_id
) AS sub ON (p.id=sub.permission_id)
, (
SELECT COUNT(*) AS nbr
FROM applications
WHERE (price<=0)
) AS total