Sql 如何在SELECT语句中重用子查询的结果
我一直在处理一些大学课程的数据,我希望优化我的查询 我使用的数据集是英国国家警察局关于停止和搜查的数据,我试图得到种族和他们停止和搜查的比例之间的相关性 我有一个查询,它将为每个警察部队和种族组合查找搜索总数、同一部队在该种族与其他种族相比的搜索百分比、全国平均百分比以及该部队平均值与全国平均值之间的差异(我知道这是一个令人困惑的问题) 这是我当前的“有效”查询:Sql 如何在SELECT语句中重用子查询的结果,sql,postgresql,Sql,Postgresql,我一直在处理一些大学课程的数据,我希望优化我的查询 我使用的数据集是英国国家警察局关于停止和搜查的数据,我试图得到种族和他们停止和搜查的比例之间的相关性 我有一个查询,它将为每个警察部队和种族组合查找搜索总数、同一部队在该种族与其他种族相比的搜索百分比、全国平均百分比以及该部队平均值与全国平均值之间的差异(我知道这是一个令人困惑的问题) 这是我当前的“有效”查询: SELECT c1.FORCE, c1.ETHNICITY, (SELECT COUNT(*) FROM
SELECT c1.FORCE,
c1.ETHNICITY,
(SELECT COUNT(*) FROM CRIMES WHERE FORCE = c1.FORCE AND ETHNICITY = c1.ETHNICITY) AS num_searches,
(ROUND(((SELECT COUNT(*) FROM CRIMES WHERE FORCE = c1.FORCE AND ETHNICITY = c1.ETHNICITY) /
(SELECT COUNT(*) FROM CRIMES WHERE FORCE = c1.FORCE)::DECIMAL), 4) * 100) AS percentage_of_force,
(SELECT ROUND((COUNT(*) / 303565::DECIMAL) * 100, 4) FROM CRIMES WHERE ETHNICITY = c1.ETHNICITY GROUP BY ETHNICITY) AS national_average,
(SELECT (ROUND(((SELECT COUNT(*) FROM CRIMES WHERE FORCE = c1.FORCE AND ETHNICITY = c1.ETHNICITY) /
(SELECT COUNT(*) FROM CRIMES WHERE FORCE = c1.FORCE)::DECIMAL), 4) * 100) - (SELECT ROUND((COUNT(*) / 303565::DECIMAL) * 100, 4) FROM CRIMES WHERE ETHNICITY = c1.ETHNICITY GROUP BY ETHNICITY)) AS difference_from_average
FROM (SELECT * FROM CRIMES) AS c1
GROUP BY c1.FORCE, c1.ETHNICITY
ORDER BY c1.FORCE, c1.ETHNICITY;
因此,我的问题是在“选择”部分多次重用同一查询
正如您从上面的查询中所看到的,与平均值的差异\u
仅仅是力量百分比减去全国平均值的结果,但是我似乎无法找到一种方法来计算这些值一次,然后在选择
部分的其他地方重复使用它们。所以我的问题是我如何才能做到这一点
其他信息
示例输入数据
示例查询结果
我正在使用PostgreSQL v11.2。诀窍是使用子选择:
SELECT f(a, b), a, c
FROM (SELECT g(c, d) AS a,
h(c) AS b,
c, d
FROM x) AS q;
你明白了。有不同的方法来简化查询。您可以使用一系列CTE来预计算不同聚合级别的结果。但我认为最有效和可读的选择是使用窗口函数
所有中间计数都可以在子查询中计算,使用(…)上的COUNT(…)
和各种PARTITION BY
选项,如下所示:
SELECT
force,
ethnicity,
COUNT(*) OVER(PARTITION BY force, ethnicity) AS cnt,
COUNT(*) OVER(PARTITION BY force) AS cnt_force,
COUNT(*) OVER(PARTITION BY ethnicity) AS cnt_ethnicity,
ROW_NUMBER() OVER(PARTITION BY force, ethnicity) AS rn
FROM crimes
然后外部查询可以计算最终结果(同时对每个元组中的第一条记录进行过滤以避免重复)
查询:
SELECT
force,
ethnicity,
cnt AS num_searches,
ROUND(cnt / cnt_force::decimal * 100, 4) AS percentage_of_force,
ROUND(cnt_ethnicity / 303565::decimal * 100, 4) AS national_average,
ROUND(cnt / cnt_force::decimal * 100, 4)
- ROUND(cnt_ethnicity / 303565::decimal * 100, 4) AS difference_from_average
FROM (
SELECT
force,
ethnicity,
COUNT(*) OVER(PARTITION BY force, ethnicity) AS cnt,
COUNT(*) OVER(PARTITION BY force) AS cnt_force,
COUNT(*) OVER(PARTITION BY ethnicity) AS cnt_ethnicity,
ROW_NUMBER() OVER(PARTITION BY force, ethnicity) AS rn
FROM crimes
) x
WHERE rn = 1
ORDER BY force, ethnicity;
:
| force | ethnicity | num_searches | percentage_of_force | national_average | difference_from_average |
| --------------- | --------- | ------------ | ------------------- | ---------------- | ----------------------- |
| metropolitan | Black | 6 | 46.1538 | 0.0020 | 46.1518 |
| metropolitan | Undefined | 1 | 7.6923 | 0.0003 | 7.6920 |
| metropolitan | White | 6 | 46.1538 | 0.0043 | 46.1495 |
| norfolk | White | 1 | 100.0000 | 0.0043 | 99.9957 |
| north-yorkshire | White | 2 | 100.0000 | 0.0043 | 99.9957 |
| northumbria | White | 1 | 100.0000 | 0.0043 | 99.9957 |
| west-yorkshire | White | 3 | 100.0000 | 0.0043 | 99.9957 |
谢谢@GMB这正是我想要的答案。我真的很感谢你花时间给我这么全面的回答!
SELECT
force,
ethnicity,
cnt AS num_searches,
ROUND(cnt / cnt_force::decimal * 100, 4) AS percentage_of_force,
ROUND(cnt_ethnicity / 303565::decimal * 100, 4) AS national_average,
ROUND(cnt / cnt_force::decimal * 100, 4)
- ROUND(cnt_ethnicity / 303565::decimal * 100, 4) AS difference_from_average
FROM (
SELECT
force,
ethnicity,
COUNT(*) OVER(PARTITION BY force, ethnicity) AS cnt,
COUNT(*) OVER(PARTITION BY force) AS cnt_force,
COUNT(*) OVER(PARTITION BY ethnicity) AS cnt_ethnicity,
ROW_NUMBER() OVER(PARTITION BY force, ethnicity) AS rn
FROM crimes
) x
WHERE rn = 1
ORDER BY force, ethnicity;
| force | ethnicity | num_searches | percentage_of_force | national_average | difference_from_average |
| --------------- | --------- | ------------ | ------------------- | ---------------- | ----------------------- |
| metropolitan | Black | 6 | 46.1538 | 0.0020 | 46.1518 |
| metropolitan | Undefined | 1 | 7.6923 | 0.0003 | 7.6920 |
| metropolitan | White | 6 | 46.1538 | 0.0043 | 46.1495 |
| norfolk | White | 1 | 100.0000 | 0.0043 | 99.9957 |
| north-yorkshire | White | 2 | 100.0000 | 0.0043 | 99.9957 |
| northumbria | White | 1 | 100.0000 | 0.0043 | 99.9957 |
| west-yorkshire | White | 3 | 100.0000 | 0.0043 | 99.9957 |