问题
I am trying to create an implicit rank in the output from the query. The problem seems to be that row_number()
is running before worth
is calculated.
SELECT
firstname,
lastname,
personid,
year,
(
SELECT COALESCE(SUM(thevalue),0)
FROM assets WHERE personidref = w.personid AND year = w.year
) AS assets ,
(
SELECT COALESCE(SUM(amount),0)
FROM liabilities WHERE personidref = w.personid AND year = w.year
) AS liabilities,
(
(SELECT COALESCE(SUM(thevalue),0)
FROM assets
WHERE personidref = w.personid AND year = w.year)
-
(SELECT COALESCE(SUM(amount),0)
FROM liabilities
WHERE personidref = w.personid AND year = w.year)
) as worth,
row_number() over(ORDER BY w.worth) as rank
FROM members w
WHERE year = 2012
ORDER BY worth DESC LIMIT 2;
The result is I am getting this:
| firstname | lastname | personid | year | assets | liabilities | worth | rank |
+-----------+----------+----------+------+--------+-------------+-------+------+
| foo | bar | 234 | 2012 | 30000 | 20 | 29980 | 32 |
| foo2 | bar2 | 5234 | 2012 | 30000 | 100 | 29900 | 69 |
Instead of this desired output:
| firstname | lastname | personid | year | assets | liabilities | worth | rank |
+-----------+----------+----------+------+--------+-------------+-------+------+
| foo | bar | 234 | 2012 | 30000 | 20 | 29980 | 1 |
| foo2 | bar2 | 5234 | 2012 | 30000 | 100 | 29900 | 2 |
Is there a way to pre-run this query and pre-sort by rank first?
回答1:
How about doubling up on the row_number()?
with enchilada as (
SELECT firstname,lastname,personid,year,(SELECT COALESCE(SUM(thevalue),0)
FROM assets WHERE personidref = w.personid) AS assets ,
(SELECT COALESCE(SUM(amount),0) FROM liabilities WHERE personidref = w.personid AND year = w.year) AS liabilities,
((SELECT COALESCE(SUM(thevalue),0) FROM assets WHERE personidref = w.personid AND year = w.year) - (SELECT COALESCE(SUM(amount),0) FROM liabilities WHERE personidref = w.personid AND year = w.year)) as worth,
row_number() over(ORDER BY w.worth) as rank
FROM members w
WHERE year = 2012
ORDER BY worth DESC LIMIT 2 )
select row_number() over (order by rank) as new_rank, * from enchilada;
回答2:
Without sample data it's hard to be sure, but if you want a ranking, why not use rank or dense_rank?
rank() over(ORDER BY w.worth) as rank
or
dense_rank() over(ORDER BY w.worth) as rank
?
Here's what I think you might be trying to do. Untested, as there's no sample data or http://sqlfiddle.com/ to test with, but:
SELECT
*,
dense_rank() OVER (ORDER BY worth)
FROM
(
SELECT
*,
assets - liabilities AS worth
FROM
(
SELECT
firstname,
lastname,
personid,
year,
(
SELECT COALESCE(SUM(a.thevalue),0)
FROM assets a WHERE a.personidref = w.personid AND a.year = w.year
) AS assets ,
(
SELECT COALESCE(SUM(l.amount),0)
FROM liabilities l WHERE l.personidref = w.personid AND l.year = w.year
) AS liabilities
FROM members w
WHERE year = 2012
) AS a_and_l
) AS net_worths
ORDER BY worth DESC
LIMIT 2;
来源:https://stackoverflow.com/questions/25732309/generating-a-ordered-sequence-rank-on-complex-query