问题
I have the following table in my database.
# select * FROM matches;
name | prop | rank
------+------+-------
carl | 1 | 4
carl | 2 | 3
carl | 3 | 9
alex | 1 | 8
alex | 2 | 5
alex | 3 | 6
alex | 3 | 8
alex | 2 | 11
anna | 3 | 8
anna | 3 | 13
anna | 2 | 14
(11 rows)
Each person is ranked at work by different properties/criterias called 'prop' and the performance is called 'rank'. The table contains multiple values of (name, prop) as the example shows. I want to get the best candidate following from some requirements. E.g. I need a candidate that have (prop=1 AND rank > 5)
and (prop=3 AND rank >= 8)
. Then we must be able to sort the candidates by their rankings to get the best candidate.
EDIT: Each person must fulfill ALL requirements
How can I do this in SQL?
回答1:
select x.name, max(x.rank)
from matches x
join (
select name from matches where prop = 1 AND rank > 5
intersect
select name from matches where prop = 3 AND rank >= 8
) y
on x.name = y.name
group by x.name
order by max(rank);
回答2:
Filtering the data to match your criteria here is quite simple (as shown by both Amir and sternze):
SELECT *
FROM matches
WHERE prop=1 AND rank>5) OR (prop=3 AND rank>=8
The problem is how to aggregate this data so as to have just one row per candidate.
I suggest you do something like this:
SELECT m.name,
MAX(DeltaRank1) AS MaxDeltaRank1,
MAX(DeltaRank3) AS MaxDeltaRank3
FROM (
SELECT name,
(CASE WHEN prop=1 THEN rank-6 ELSE 0 END) AS DeltaRank1,
(CASE WHEN prop=3 THEN rank-8 ELSE 0 END) AS DeltaRank3,
FROM matches
) m
GROUP BY m.name
HAVING MaxDeltaRank1>0 AND MaxDeltaRank3>0
SORT BY MaxDeltaRank1+MaxDeltaRank3 DESC;
This will order the candidates by the sum of how much they exceeded the target rank in prop1 and prop3. You could use different logic to indicate which is best though.
In the case above, this should be the result:
name | MaxDeltaRank1 | MaxDeltaRank3
------+---------------+--------------
alex | 3 | 0
... because neither anna nor carl reach both the required ranks.
回答3:
A typical case of relational division. We assembled a whole arsenal of techniques under this related question:
How to filter SQL results in a has-many-through relation
Assuming you want the minimum rank of a person, I might solve your particular case with LEAST():
SELECT m1.name, LEAST(m1.rank, m2.rank, ...) AS best_rank
FROM matches m1
JOIN matches m2 USING (name)
...
WHERE m1.prop = 1 AND m1.rank > 5
AND m2.prop = 3 AND m2.rank >= 8
...
ORDER BY best_rank;
Also assuming name
to be unique per individual person. You'd probably use some kind of foreign key to a pk column of a person
table in reality.
And if you have such a person
table like you should, the best rank would be stored in a column there ...
回答4:
If I understand you question, then you just need to execute the following operation:
SELECT * FROM matches where (prop = 1 AND rank > 5) OR (prop = 3 AND rank >= 8) ORDER BY rank
It gives you the canidates that either have prop=1 and rank > 5 or prop=3 and rank >= 8 sorted by their rankings.
来源:https://stackoverflow.com/questions/24286141/matching-algorithm-in-sql