воскресенье, 17 октября 2010 г.

Ранкинг (Ranking). SQL запросы с рангом (Rank).

Ранкинг (Ranking) - это предоставление информации о соответствии найденной записи определенному запросу. Это соответствие в простейшем случае можно отобразить в процентном соостветсвии. Т.е. записи удовлетворяющие всем критериям имеют 100%-ный ранкинг.

Реализация ранкинга может показаться достаточно сложной задачей. Но это только так кажется. SQL может взять эту задачу на себя! Для примера я использовал MySQL, реально использовал MSSQL.

Итак, таблица:
CREATE TABLE `test_db`.`person` (
`id` INT NOT NULL,
`name` VARCHAR (100),
`age` int ,
PRIMARY KEY (`id`)
)

Наполним данными:
INSERT INTO test_db.person VALUES (1,'Ralf', 20),(2,'Peter', 30),(3,'Patrick', 40);

Найдем записи, которые соответсвуют одному из трех критериев:
- все старше 25;
- все младше 35;
- имена начинаются на "P";

Запрос может выглядеть так:
SELECT p.id, p.name, p.age FROM test_db.person p
WHERE age > 25 OR age < 35 OR name Like 'P%'


А результат запроса, так:
id, name, age
------------
1,'Ralf', 20
2,'Peter', 30
3,'Patrick',40

Добавим ранкинг (ranking). Объяснять не буду, все очень просто:
SELECT p.id, p.name, p.age, (100/3)*under1.hit + (100/3)*under2.hit + (100/3)*under3.hit AS rank FROM test_db.person p
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age > 25) AS under1 On under1.id = p.id
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age < 35) AS under2 On under2.id = p.id LEFT JOIN (Select id, 1 As hit from test_db.person WHERE name like 'p%') AS under3 On under3.id = p.id WHERE age > 25 OR age < 35 OR name like 'p%'


Результат:
id, name, age, rank
------------
1,'Ralf', 20, null
2,'Peter', 30, null
3,'Patrick', 40, null

Почти то, что нужно, но есть проблема с приведением арфиметического результа к null:
Для этого в MySql можно использовать функцию IFNULL (в MSSQL это функция ISNULL):
SELECT p.id, p.name, p.age, (100/3)*IFNULL(under1.hit, 0) + (100/3)*IFNULL(under2.hit,0) + (100/3)*IFNULL(under3.hit,0) AS rank FROM test_db.person p
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age > 25) AS under1 On under1.id = p.id
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age < 35) AS under2 On under2.id = p.id LEFT JOIN (Select id, 1 As hit from test_db.person WHERE name like 'p%') AS under3 On under3.id = p.id WHERE age > 25 OR age < 35 OR name like 'p%'


Результат:
id, name, age, rank
------------
1,'Ralf', 20, 33.333
2,'Peter', 30, 100.000
3,'Patrick', 40, 66.666

Комментариев нет: