Двойной запрос

lioncub

Новичок
Двойной запрос

Есть три таблицы:
radcheck - хранит в себе id пользователя и его логин (id,username);
radreply - хранит логин, атрибут параметра и сам параметр IP,Protocol (username,attribute,value);
traffic_sum - хранит id пользователя и его сумму(id,money).
Хочу вывести все IP у кого сумма "0" по протоколу "PPP"

SELECT radreply.`Value` FROM
radcheck,
radreply,
traffic_sum
WHERE
radreply.`UserName` = radcheck.`UserName` AND
traffic_sum.`id_user` = radcheck.`id` AND
radreply.`Attribute` = 'Framed-IP-Address' AND
radreply.`UserName` = (SELECT UserName FROM radreply WHERE `Attribute` = 'Protocol' AND `Value` = 'PPP') AND
traffic_sum.`money` = 0;

Ошибка: SQL Error: Subquery returns more than 1 row

Как правильно сделать запрос?
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
Используй вместо =
IN
 

PILOT

Новичок
Re: Двойной запрос

Автор оригинала: lioncub

radreply.`UserName` = (SELECT UserName FROM radreply WHERE `Attribute` = 'Protocol' AND `Value` = 'PPP') AND

Как правильно сделать запрос?
Рекомендую использовать derived запрос вместо subquery.
 

lioncub

Новичок
А как будет выглядеть с join'ом и derived'ом?
Хотелось бы посмотреть для сравнения, и чем они лучше?
 

Dovg

Продвинутый новичок
да да, чем они лучше?

Я сколько не тестировал, получалось примерно одинаково по скорости
 

PILOT

Новичок
Автор оригинала: Dovg
да да, чем они лучше?

Я сколько не тестировал, получалось примерно одинаково по скорости
Можно сказать тем, что subquery совсем неправильно работают. Настолько, что их использовать просто нельзя. И даже не знаю как уж тестировалось, что результаты одинаковые. Derived обычно используют как некоторый workaround, когда нужен вложенный запрос. Делается join (select blabla) as t_alias. При этом он реально выполняется перед запросом, данные кладутся в память (если помещаются) и соответственно дальше идёт обычный join. Конкретно в этой задаче естественно нужно использовать простой join. Я просто даже задачку, честно говоря, не посмотрел, а просто увидел вложенный селект, и что проблема решается заменой на in :)
Ссылка на мануал join'a, наверное, самая часто встречаемая на этом форуме, а посему автору предлагается найти её самостоятельно.
 

Dovg

Продвинутый новичок
PILOT
И даже не знаю как уж тестировалось, что результаты одинаковые
вот так вот тестировал :)

а у вас есть результаты тестов, где subquery заметно проигрывает join ?
 

Gas

может по одной?
да да, чем они лучше?
IN (SUBQUERY) : mysql для каждой записи внешней таблицы вызывает подзапрос, а не вначале выполняет его 1 раз и использует результат. Это исправлено в mysql 6.

1. http://bugs.mysql.com/bug.php?id=9090
2. http://www.sql.ru/forum/actualthread.aspx?bid=6&tid=567127 (тут много чего обсуждается, в том числе и это).

Что касается derived query - то его результат (имхо) это temporary table, естественно без индексов. Но что будет быстрее join всей таблицы по индексам или только найденных записей в результате derived query - сказать однозначно нельзя, всё зависит от данных и запроса.
Хотя в примере автора, мне кажется быстрее будет повторный обычный join таблицы radreply, вместо IN (...) или JOIN (SELECT ...).
 

lioncub

Новичок
SELECT radreply.`Value` FROM
radcheck,
radreply,
traffic_sum
LEFT JOIN
(SELECT UserName FROM radreply WHERE `Attribute` = 'Protocol' AND `Value` = 'PPP')
WHERE
radreply.`UserName` = radcheck.`UserName` AND
traffic_sum.`id_user` = radcheck.`id` AND
radreply.`Attribute` = 'Framed-IP-Address' AND
traffic_sum.`money` = 0;

Требует SQL Error: Every derived table must have its own alias
А как без derived сделать?
 

Balloon

Новичок
а как на счет такого варианта:
SELECT rr2.value FROM radcheck as rc
LEFT JOIN radreply as rr1 ON rr1.username = rc.username
LEFT JOIN radreply as rr2 ON rr2.username = rc.username
LEFT JOIN traffic_sum as ts ON ts.id_user = rc.id
WHERE
rr1.attribute = 'Protocol' AND rr1.value = 'PPP'
AND rr2.attribute = 'Framed-IP-Address'
AND ts.money = 0

?
 
Сверху