LINUX.ORG.RU

Хитрый SQL-запрос


0

1

Добрый день.

Как всегда, хочется странного. Есть таблица, содержащая поля: дата_сеанса, номер_телефона, полученные_данные, индекс. Номеров телефона уникальных 20 штук, каждый из них может звонить в случайное время. Что хочу? Хочу сделать VIEW, в котором будут храниться только последние по времени сеансы для каждого номера. Как такое можно сделать? Для получения самого последнего сеанса я делал так:

 
CREATE VIEW `last_data` AS 
select 
`date` AS `date`,
`phone` AS `phone`,
`data` AS `data`
from `monitoringtable`
order by `index` desc limit 1;

Но это просто. А вот как получить то, что требуется сейчас? Если отсортировать по дате, а затем по номеру телефона, а затем взять последние 20, то может получиться, что некоторые номера туда не попадут, потому что у них слишком давно был сеанс. Делать VIEW для каждого номера отдельно тоже расточительно.



Последнее исправление: decadent (всего исправлений: 1)

GROUP BY `phone` разве не подойдет?

madcore ★★★★★
()
Ответ на: комментарий от BaBL

А, нет, не работает. Такой запрос выбирает первые сеансы, а мне нужно последние. Введение ключевого слова DESC сортирует по убыванию результат, уже извлеченный через GROUP BY, а в обратном порядке MySQL ругается на неправильный синтаксис.

decadent
() автор топика
Ответ на: комментарий от decadent
CREATE VIEW `last_data` AS 
select 
`date` AS `date`,
`phone` AS `phone`,
`data` AS `data`
from (
     select
          max(date) mdate,
          `phone`
     from `monitoringtable`
      group by `phone`
) md
join monitoringtable mt on `md`.`mdate`=`mt`.`mdate` and `md`.`phone` = `mt`.`phone`

попробуй так

BaBL ★★★★★
()
Последнее исправление: BaBL (всего исправлений: 1)
Ответ на: комментарий от decadent

Это полурабочий костыль, который не на каждой СУБД заработает, а на тех, где заработает, еще бабушка на двое сказала, что работать будет именно так, как задумано.

Во-первых, если делается группировка, в select (и order) можно указывать только поля, по которым делается группировка, и группирующие функции (max, sum и т.д.). Во-вторых, если пренебрегаешь первым правилом, учитывай, что конкретно твоя СУБД в запросе 'select id,value,date from xxx order by id' скорее всего вернет не записи с максимальной датой, а «последние» записи по каждому ID, теоретически value и date могут оказаться вовсе из разных записей.

Правильно подобные задачи решаются отдельным подзапросом(-ами), сначала находятся идентификаторы записей, соответствующие группировкам и условиям, потом уже по этим идентификаторам вытягиваются все необходимые данные.

staseg ★★★★★
()
Ответ на: комментарий от BaBL

Так я об этом и писал. В результате этого запрос я получаю первые записи для каждого номера телефона, которые потом сортируются по убыванию даты. А мне нужно «наоборот» — получить записи с «максимальной» датой.

decadent
() автор топика
Ответ на: комментарий от decadent

попробуй так:
Хитрый SQL-запрос (комментарий)
должно работать

делай со спецификой своей СУБД само собой, я для mysql писал, в других могут быть проблемы с полем phone вне группировки. Тогда можешь сгруппировать по phone и mdate, они все равно будут уникальны.

BaBL ★★★★★
()
Ответ на: комментарий от staseg

Угу, похоже, придется повозиться с подзапросами.

decadent
() автор топика
Ответ на: комментарий от BaBL

Попробовал, спасибо. Таки заработало. Единственное — пришлось указывать `mt`.`phone` AS `phone`, потому как после JOIN в таблице оказывалось два поля с именем `phone`.

decadent
() автор топика
Ответ на: комментарий от BaBL

Ха! Если делать просто select, все работает отлично. А вот если на его базе делать VIEW, снова получаю ошибку:

#1349 - View's SELECT contains a subquery in the FROM clause

Версия mysql 5.5.22-0ubuntu1.

decadent
() автор топика
Ответ на: комментарий от decadent

Ха! Если делать просто select, все работает отлично. А вот если на его базе делать VIEW, снова получаю ошибку:

Да, у MySQL есть такое ограничение, забыл про него =(

Тогда разве что так:

CREATE VIEW `md` AS
select
     max(date) mdate,
      `phone`
from `monitoringtable`
group by `phone`;

CREATE VIEW `last_data` AS 
select 
`date` AS `date`,
`phone` AS `phone`,
`data` AS `data`
from md
join monitoringtable mt on `md`.`mdate`=`mt`.`mdate` and `md`.`phone` = `mt`.`phone`;
работать будет медленнее само собой...

BaBL ★★★★★
()
Последнее исправление: BaBL (всего исправлений: 1)
Ответ на: комментарий от staseg

Как оказалось, в MySQL при создании VIEW нельзя использовать подзапросы. Есть ли какой-нибудь обходной путь? Или только создавать временную VIEW, и потом из нее выбирать нужное?

decadent
() автор топика
Ответ на: комментарий от decadent

Насколько я знаю, в один запрос такую задачу не решить.

С какой целью вообще создается основная view? Если она временная и выступает в роли одного из шагов вычисления большого запроса, вместо view скорее всего лучше использовать полноценную выборку в переменную.

staseg ★★★★★
()
Ответ на: комментарий от staseg

Насколько я знаю, в один запрос такую задачу не решить.

Неприятно.

С какой целью вообще создается основная view?

В общем да, она временная. Клиенту в основном нужно знать именно результаты последней сессии с каждого номера телефона, а предыдущие могут потребоваться редко. Поэтому я и захотел выделить последние сессии в отдельную VIEW.

decadent
() автор топика
Ответ на: комментарий от xorik

А какая альтернатива? Клиенту нужно знать результаты последних сессий для каждого номера. Каждый раз тормошить основную таблицу с клиента?

decadent
() автор топика
Ответ на: комментарий от decadent

А что не так? Как будто через представление эти таблицы не «тормошаться»

xorik ★★★★★
()

select distinct on (phone) phone, date, data from tbl order by phone, date desc

но я не знаю есть ли distinct on в mysql.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.