基于联接中的组合列获取用户排名的问题 table
Issue with getting the rank of a user based on combined columns in a join table
我有 users
table,每个用户都有 flights
table 的航班。每个航班在 airports
table 内都有出发和到达机场关系。我需要做的是为每个用户计算出发和到达列(flights.departure_airport_id
和 flights.arrival_airport_id
)的唯一机场,然后通过 dense_rank
为他们分配一个排名,然后检索给定用户 ID 的排名。
基本上,我需要根据所有用户飞抵或飞出的唯一机场数量对所有用户进行排序,然后获得特定用户的排名。
这是我目前的情况:
SELECT u.rank FROM (
SELECT
users.id,
dense_rank () OVER (ORDER BY count(DISTINCT (flights.departure_airport_id, flights.arrival_airport_id)) DESC) AS rank
FROM users
LEFT JOIN flights ON users.id = flights.user_id
GROUP BY users.id
) AS u WHERE u.id = 'uuid';
这有效,但实际上 return 并没有达到预期的结果,因为 count(DISTINCT (flights.departure_airport_id, flights.arrival_airport_id))
计算的是组合的机场 ID,而不是单独计算每个唯一的机场 ID。无论如何,我就是这样理解它的工作原理的……我猜我需要以某种方式在机场 ID 列上使用 UNION
连接,但不知道该怎么做。
我正在使用 Postgres 13.0。
您计算的是 (departure_airport_id、arrival_airpot_id) 的不同对。正如您所建议的,您可以使用 union
获取一列机场 ID(无论它们是出发机场还是到达机场),然后对其应用计数:
SELECT user_id, DENSE_RANK() OVER (ORDER BY cnt DESC) AS user_rank
FROM (SELECT u.id AS user_id, COALESCE(cnt, 0) AS cnt
FROM users u
LEFT JOIN (SELECT user_id, COUNT DISTINCT(airport_id) AS cnt
FROM (SELECT user_id, departure_airport_id AS airport_id
FROM flights
UNION
SELECT user_id, arrival_airport_id AS airport_id
FROM flights) x
GROUP BY u.id) f ON u.id = f.user_id) t
我会推荐一个横向连接到 unpivot,然后聚合和排名:
select *
from (
select f.user_id,
dense_rank() over(order by count(distinct a.airport_id) desc) rn
from flights f
cross join lateral (values
(f.departure_airport_id), (f.arrival_airport_id)
) a(airport_id)
group by f.user_id
) t
where user_id = 'uuid'
您并不真的需要 users
table 来满足您的需求,除非您确实想让用户无需任何航班(他们都具有相同的最高级别)。如果是:
select *
from (
select u.id,
dense_rank() over(order by count(distinct a.airport_id) desc) rn
from users u
left join flights f on f.user_id = u.id
left join lateral (values
(f.departure_airport_id), (f.arrival_airport_id)
) a(airport_id) on true
group by u.id
) t
where id = 'uuid'
我有 users
table,每个用户都有 flights
table 的航班。每个航班在 airports
table 内都有出发和到达机场关系。我需要做的是为每个用户计算出发和到达列(flights.departure_airport_id
和 flights.arrival_airport_id
)的唯一机场,然后通过 dense_rank
为他们分配一个排名,然后检索给定用户 ID 的排名。
基本上,我需要根据所有用户飞抵或飞出的唯一机场数量对所有用户进行排序,然后获得特定用户的排名。
这是我目前的情况:
SELECT u.rank FROM (
SELECT
users.id,
dense_rank () OVER (ORDER BY count(DISTINCT (flights.departure_airport_id, flights.arrival_airport_id)) DESC) AS rank
FROM users
LEFT JOIN flights ON users.id = flights.user_id
GROUP BY users.id
) AS u WHERE u.id = 'uuid';
这有效,但实际上 return 并没有达到预期的结果,因为 count(DISTINCT (flights.departure_airport_id, flights.arrival_airport_id))
计算的是组合的机场 ID,而不是单独计算每个唯一的机场 ID。无论如何,我就是这样理解它的工作原理的……我猜我需要以某种方式在机场 ID 列上使用 UNION
连接,但不知道该怎么做。
我正在使用 Postgres 13.0。
您计算的是 (departure_airport_id、arrival_airpot_id) 的不同对。正如您所建议的,您可以使用 union
获取一列机场 ID(无论它们是出发机场还是到达机场),然后对其应用计数:
SELECT user_id, DENSE_RANK() OVER (ORDER BY cnt DESC) AS user_rank
FROM (SELECT u.id AS user_id, COALESCE(cnt, 0) AS cnt
FROM users u
LEFT JOIN (SELECT user_id, COUNT DISTINCT(airport_id) AS cnt
FROM (SELECT user_id, departure_airport_id AS airport_id
FROM flights
UNION
SELECT user_id, arrival_airport_id AS airport_id
FROM flights) x
GROUP BY u.id) f ON u.id = f.user_id) t
我会推荐一个横向连接到 unpivot,然后聚合和排名:
select *
from (
select f.user_id,
dense_rank() over(order by count(distinct a.airport_id) desc) rn
from flights f
cross join lateral (values
(f.departure_airport_id), (f.arrival_airport_id)
) a(airport_id)
group by f.user_id
) t
where user_id = 'uuid'
您并不真的需要 users
table 来满足您的需求,除非您确实想让用户无需任何航班(他们都具有相同的最高级别)。如果是:
select *
from (
select u.id,
dense_rank() over(order by count(distinct a.airport_id) desc) rn
from users u
left join flights f on f.user_id = u.id
left join lateral (values
(f.departure_airport_id), (f.arrival_airport_id)
) a(airport_id) on true
group by u.id
) t
where id = 'uuid'