使用 CTE 和 Window 函数获取预算内的招聘人数
Use CTE and Window Function to get the number of hiring under a budget
我有一个 table candidates
,其中有三列 id
、position
和 salary
。
生成 table 的代码是
create table candidates (
id int primary key,
position varchar not null,
salary int not null
);
insert into candidates values (1, 'junior', 10500);
insert into candidates values (2, 'senior', 15000);
insert into candidates values (3, 'senior', 35000);
insert into candidates values (4, 'junior', 8000);
insert into candidates values (5, 'senior', 30000);
insert into candidates values (6, 'senior', 25000);
insert into candidates values (7, 'junior', 30000);
insert into candidates values (8, 'senior', 50000);
insert into candidates values (9, 'senior', 30000);
insert into candidates values (10, 'junior', 7000);
insert into candidates values (11, 'junior', 8000);
insert into candidates values (12, 'senior', 33000);
insert into candidates values (13, 'junior', 5000);
insert into candidates values (14, 'senior', 47000);
insert into candidates values (15, 'junior', 12000);
我的预算是150000,我需要尽可能多地聘请低成本的前辈,剩下的钱,我可以尽可能多地聘请后辈。我写这段代码是为了获取高年级和低年级的钱的累计金额。
SELECT id, position, salary, SUM(salary) OVER (PARTITION BY position ORDER BY salary) AS cum_salary
FROM candidates
ORDER BY position DESC, salary;
我得到的输出是
id
position
salary
cum_salary
2
senior
15000
15000
6
senior
25000
40000
5
senior
30000
100000
9
senior
30000
100000
12
senior
33000
133000
3
senior
35000
168000
14
senior
47000
215000
8
senior
50000
265000
13
junior
5000
5000
10
junior
7000
12000
11
junior
8000
28000
4
junior
8000
28000
1
junior
10500
38500
15
junior
12000
50500
7
junior
30000
80500
我可以看到我可以用133000(不到150000)雇用5个前辈,用剩下的钱(150000 - 133000 = 17000)雇用两个后辈。所以,最终的输出应该是这样的
senior
5
junior
2
我如何在 POSTGRESQL 9.6 中使用 CTE 和 Window 函数编写此查询以获得我需要的大型数据集的输出类型,而手动操作并不总是可行?
PS: 我不是 Postgres 9.6 的专家用户。
这样就可以了:
WITH cte AS (
SELECT position, salary
, sum(salary) OVER w AS cum_salary
, row_number() OVER w AS count
FROM candidates
WINDOW w AS (PARTITION BY position ORDER BY salary)
)
, sen AS (
SELECT position, cum_salary, count
FROM cte
WHERE position = 'senior'
AND cum_salary <= 150000
ORDER BY cum_salary DESC
LIMIT 1
)
SELECT position, count FROM sen
UNION ALL
( -- parentheses required
SELECT position, count
FROM cte
WHERE position = 'junior'
AND cum_salary <= (SELECT 150000 - cum_salary FROM sen)
ORDER BY cum_salary DESC
LIMIT 1
);
db<>fiddle here
只要您可以硬编码 CTE 的数量,就会如下所示。
PS: 你开局不错。也可能有一种方法可以优化下面的代码。祝你好运 ;)
with seniors as (
SELECT
id
, position
, salary
, SUM(salary) OVER (PARTITION BY position ORDER BY salary) AS cum_salary
FROM candidates
where position = 'senior'
)
,juniors as (
SELECT
id
, position
, salary
, SUM(salary) OVER (PARTITION BY position ORDER BY salary) AS cum_salary
FROM candidates
where position = 'junior'
)
,seniors_canhire as (
select
id
, position
, salary
from seniors
where cum_salary <= 150000
)
,juniors_canhire as (
SELECT
id
, position
, salary
FROM juniors
where cum_salary <= (select 150000-sum(salary) from seniors_canhire)
)
select *
from seniors_canhire
union all
select *
from juniors_canhire
我有一个 table candidates
,其中有三列 id
、position
和 salary
。
生成 table 的代码是
create table candidates (
id int primary key,
position varchar not null,
salary int not null
);
insert into candidates values (1, 'junior', 10500);
insert into candidates values (2, 'senior', 15000);
insert into candidates values (3, 'senior', 35000);
insert into candidates values (4, 'junior', 8000);
insert into candidates values (5, 'senior', 30000);
insert into candidates values (6, 'senior', 25000);
insert into candidates values (7, 'junior', 30000);
insert into candidates values (8, 'senior', 50000);
insert into candidates values (9, 'senior', 30000);
insert into candidates values (10, 'junior', 7000);
insert into candidates values (11, 'junior', 8000);
insert into candidates values (12, 'senior', 33000);
insert into candidates values (13, 'junior', 5000);
insert into candidates values (14, 'senior', 47000);
insert into candidates values (15, 'junior', 12000);
我的预算是150000,我需要尽可能多地聘请低成本的前辈,剩下的钱,我可以尽可能多地聘请后辈。我写这段代码是为了获取高年级和低年级的钱的累计金额。
SELECT id, position, salary, SUM(salary) OVER (PARTITION BY position ORDER BY salary) AS cum_salary
FROM candidates
ORDER BY position DESC, salary;
我得到的输出是
id | position | salary | cum_salary |
---|---|---|---|
2 | senior | 15000 | 15000 |
6 | senior | 25000 | 40000 |
5 | senior | 30000 | 100000 |
9 | senior | 30000 | 100000 |
12 | senior | 33000 | 133000 |
3 | senior | 35000 | 168000 |
14 | senior | 47000 | 215000 |
8 | senior | 50000 | 265000 |
13 | junior | 5000 | 5000 |
10 | junior | 7000 | 12000 |
11 | junior | 8000 | 28000 |
4 | junior | 8000 | 28000 |
1 | junior | 10500 | 38500 |
15 | junior | 12000 | 50500 |
7 | junior | 30000 | 80500 |
我可以看到我可以用133000(不到150000)雇用5个前辈,用剩下的钱(150000 - 133000 = 17000)雇用两个后辈。所以,最终的输出应该是这样的
senior | 5 |
---|---|
junior | 2 |
我如何在 POSTGRESQL 9.6 中使用 CTE 和 Window 函数编写此查询以获得我需要的大型数据集的输出类型,而手动操作并不总是可行?
PS: 我不是 Postgres 9.6 的专家用户。
这样就可以了:
WITH cte AS (
SELECT position, salary
, sum(salary) OVER w AS cum_salary
, row_number() OVER w AS count
FROM candidates
WINDOW w AS (PARTITION BY position ORDER BY salary)
)
, sen AS (
SELECT position, cum_salary, count
FROM cte
WHERE position = 'senior'
AND cum_salary <= 150000
ORDER BY cum_salary DESC
LIMIT 1
)
SELECT position, count FROM sen
UNION ALL
( -- parentheses required
SELECT position, count
FROM cte
WHERE position = 'junior'
AND cum_salary <= (SELECT 150000 - cum_salary FROM sen)
ORDER BY cum_salary DESC
LIMIT 1
);
db<>fiddle here
只要您可以硬编码 CTE 的数量,就会如下所示。 PS: 你开局不错。也可能有一种方法可以优化下面的代码。祝你好运 ;)
with seniors as (
SELECT
id
, position
, salary
, SUM(salary) OVER (PARTITION BY position ORDER BY salary) AS cum_salary
FROM candidates
where position = 'senior'
)
,juniors as (
SELECT
id
, position
, salary
, SUM(salary) OVER (PARTITION BY position ORDER BY salary) AS cum_salary
FROM candidates
where position = 'junior'
)
,seniors_canhire as (
select
id
, position
, salary
from seniors
where cum_salary <= 150000
)
,juniors_canhire as (
SELECT
id
, position
, salary
FROM juniors
where cum_salary <= (select 150000-sum(salary) from seniors_canhire)
)
select *
from seniors_canhire
union all
select *
from juniors_canhire