КАК ANY МОЖЕТ СТАТЬ НЕОДНОЗНАЧНЫМ?
Как говорилось выше, ANY не полностью однозначен. Если мы создаём запрос, чтобы выбрать заказчиков, которые имеют больший рейтинг, чем любой заказчик в Риме, мы можем получить вывод, который несколько отличается от того, что мы ожидали (как показано в Рисунке 13.5):
SELECT * FROM Customers WHERE rating > ANY (SELECT rating FROM Customers WHERE city = Rome);
В английском языке способ, которым мы обычно склонны интерпретировать оценку "больше, чем любой (где city = Rome) ", должен вам сообщить, что это значение оценки должно быть выше, чем значение оценки в каждом случае, где значение city = Rome. Однако это не так в случае с ANY, используемом в SQL. ANY оценивает как true, если подзапрос находит любое значение, которое делает условие верным.
=============== SQL Execution Log ============ | | | SELECT * | | FROM Customers | | WHERE rating > ANY | | (SELECT rating | | FROM Customers | | WHERE city = 'Rome'); | | ============================================= | | cnum cname city rating snum | | ----- -------- ---- ------ ------ | | 2002 Giovanni Rome 200 1003 | | 2003 Liu San Jose 200 1002 | | 2004 Grass Berlin 300 1002 | | 2008 Cisneros San Jose 300 1007 | =============================================
Рисунок 13.5 Как операция "больше"(>) интерпретируется ANY
Если мы оценим ANY способом, использующим грамматику английского языка, то только заказчики с оценкой 300 будут превышать Giovanni, который находится в Риме и имеет оценку 200. Однако подзапрос ANY также находит Pereira в Риме с оценкой 100. Так как все заказчики с оценкой 200 были выше этой, они будут выбраны, даже если имелся другой заказчик из Рима (Giovanni), чья оценка не была выше (фактически то, что один из выбранных заказчиков также находится в Риме, несущественно). Так как подзапрос произвел по крайней мере одно значение, которое сделает предикат верным в отношении этих строк, строки были выбраны. Чтобы дать другой пример, предположим, что мы должны были выбирать все заказы на сумму, которая была больше, чем по крайней мере один из заказов на 6-е октября:
SELECT * FROM Orders WHERE amt > ANY ( SELECT amt FROM Orders WHERE odate = 10/06/1990);
Вывод для этого запроса показан на Рисунке 13.6.
Даже если самая высокая сумма приобретений в таблице (9891.88) имелась на 6-е октября, предыдущая строка имеет более высокое значение суммы, чем другая строка на 6-е октября, которая имела значение суммы = 1309.95. Имея реляционную операцию ">=" вместо просто " > ", эта строка будет также выбрана, потому что она равна самой себе.
Конечно, вы можете использовать ANY с другой SQL-техникой, например, с техникой объединения.
Этот запрос будет находить все заказы со значением суммы меньше, чем значение любой суммы для заказчика в San Jose (вывод показан на Рисунке 13.7):
SELECT * FROM Orders WHERE amt < ANY (SELECT amt FROM Orders A, Customers b WHERE a.cnum = b.cnum AND b.city = " San Jose');
Даже если наименьший заказ в таблице был для заказчика из San Jose, то был второй наибольший; следовательно, почти все строки будут выбраны. Простой запомните, что < ANY это значение, меньшее, чем наибольшее выбранное значение, а > ANY - значение, большее, чем наименьшее выбранное значение.
=============== SQL Execution Log ============== | | | SELECT * | | FROM Orders | | WHERE amt > ANY | | (SELECT amt | | FROM Orders | | WHERE odate = 10/06/1990); | | =============================================== | | onum amt odate cnum snum | | ----- -------- ---------- ----- ------ | | 3002 1900.10 10/03/1990 2007 1004 | | 3005 5160.45 10/03/1990 2003 1002 | | 3009 1713.23 10/04/1990 2002 1003 | | 3008 4723.00 10/05/1990 2006 1001 | | 3011 9891.88 10/06/1990 2006 1001 | ================================================
Рисунок 13.6 Выбрано значение, большее чем любое (ANY) на 6-е октября
=============== SQL Execution Log ============== | | | WHERE amt > ANY | | (SELECT amt | | FROM Orders a, Customers b | | WHERE a.cnum = b.cnum | | AND b.city = 'San Jose'); | | =============================================== | | onum amt odate cnum snum | | ----- -------- ---------- ----- ------ | | 3001 18.69 10/03/1990 2008 1007 | | 3003 767.10 10/03/1990 2001 1001 | | 3002 1900.10 10/03/1990 2007 1004 | | 3006 1098.10 10/03/1990 2008 1007 | | 3009 1713.23 10/04/1990 2002 1003 | | 3007 75.10 10/04/1990 2004 1002 | | 3008 4723.00 10/05/1990 2006 1001 | | 3010 1309.88 10/06/1990 2004 1002 | ================================================
Рисунок 13.7 Использование ANY с объединением
Фактически вышеуказанные команды весьма похожи на следующие (вывод показан на Рисунке 13.8):
SELECT * FROM Orders WHERE amt < (SELECT MAX amt FROM Orders A, Customers b WHERE a.cnum = b.cnum AND b.city = " San Jose');
=============== SQL Execution Log ============== | | | WHERE amt < | | (SELECT MAX (amt) | | FROM Orders a, Customers b | | WHERE a.cnum = b.cnum | | AND b.city = 'San Jose'); | | =============================================== | | onum amt odate cnum snum | | ----- -------- ---------- ----- ------ | | 3002 1900.10 10/03/1990 2007 1004 | | 3005 5160.45 10/03/1990 2003 1002 | | 3009 1713.23 10/04/1990 2002 1003 | | 3008 4723.00 10/05/1990 2006 1001 | | 3011 9891.88 10/06/1990 2006 1001 | ================================================
Рисунок 13.8 Использование агрегатной функции вместо ANY