За последние 24 часа нас посетили 170686 программистов и 3027 роботов. Сейчас ищут 1659 программистов ...

т.н. срез значений

Тема в разделе "MySQL", создана пользователем ShamahN, 2 апр 2010.

  1. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Есть некоторая табличка с историей изменений какой-либо характеристики. Таких характеристик достаточно много и изменяются они достаточно часто. Для таблички я придумал структуру (в принципе, тривиально)
    Код (Text):
    1.  
    2. id (int, key)
    3. value (float)
    4. time_point (datetime)
    Задача: в любой момент времени, надо получить набор актуальных (чаще всего последних) показаний характеристик.

    На ум пришло одно простое решение - сделать еще табличку, в которой и держать актуальные значения характеристик. В общем, неплохо работает. Но неразрешенной остается проблема получения характеристик актуальных на какой-нибудь прошлый период.
    Буду благодарен любой помощи
     
  2. Luge

    Luge Старожил

    С нами с:
    2 фев 2007
    Сообщения:
    4.680
    Симпатии:
    1
    Адрес:
    Минск
    брр, не понял, а чем выборка по дате не подходит?
     
  3. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    приведу для примера несколько записей :)
    Код (Text):
    1.  
    2. id    value    time_point
    3. 1     10        01.01.2010 00-00-00
    4. 1     11        02.01.2010 00-00-00
    5. 1     16        02.01.2010 01-00-00
    6. 2     13        01.01.2010 00-00-00
    7. 2     15        01.01.2010 00-59-00
    8. 3     99        03.01.2010 00-00-00
    9. ...
    Ну и надо выбрать все значения, актуальные на, допустим на 01.01.2010 00-59-00
    Очевидно будет предположить, что это будет 2е записи
    Код (Text):
    1.     id     value
    2. 1. 1      10
    3. 2. 2      15
    а на 01.02.2010 00-00-00 набор будет уже следующим:
    Код (Text):
    1.     id     value
    2. 1. 1      16
    3. 2. 2      15
    4. 3. 3      99
     
  4. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    [sql]select id, value from table as t
    where value in (select value as val from table where id=t.id and time_point<$date order by time_point desc limit 1)[/sql]
     
  5. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Volt(220)
    спасибо =) то что доктор прописал. Моск мой не дошел до limit 1
    вот, если для кого еще задача осталась непонятной, я поизвращался и изобразил её :)
    [​IMG]
    Где собственно, цвет полосочки характеризует значение величины.
    Еще раз спасибо
     
  6. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Опачки (
    This version of MySQL doesn't yet support 'LIMIT _IN/ALL/ANY/SOME subquery'

    что же делать((

    версия 5.4.3-beta-community
     
  7. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    [sql]WHERE MAX()< date
    GROUP BY id
    [/sql]
    Причем должно сработать без подзапроса вовсе
     
  8. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Simpliest
    а можно расширить) для приведенного примера полностью запрос. Я пока не сильно силен в мускуле ;)
     
  9. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Simpliest
    Одно из двух: либо я совсем не понимаю действие конструкции MAX()< date.
    либо придется использовать join для вытаскивания value.

    ShamahN
    Как вариант можно перенести запрос из where в from и использовать join.
     
  10. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Simpliest
    Код (Text):
    1. SELECT
    2. `values`.id,
    3. `values`.account_id,
    4. `values`.value,
    5. `values`.time_point,
    6. `values`.user_id
    7. FROM
    8. `values`
    9. WHERE
    10. MAX(`values`.time_point) <  '2010-04-02 14:48:25'
    11. GROUP BY
    12. `values`.account_id
    Пишет: неверное использование group function. Если убрать MAX то все работает, но не так как надо. Он не выбирает последнее значение
     
  11. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    ShamahN
    А что быдет если where заменить на Having (и перенести после group by, естественно)?
     
  12. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Ну парни, подумать чуток?
    агрегатные функции нельзя использовать в WHERE

    HAVING MAX(time_point) < date
     
  13. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    да, один нюанс, при больших таблицах, выгоднее может оказаться таки JOIN или подзапрос
    поскольку HAVING вызывает filesort.
     
  14. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    ну и до кучи:

    [sql]select value from table as t join
    (select id, max(time_point) as mtp from table where time_point<$date group by id) as actT
    on t.id=actT.id and t.time_point=actT.mtp[/sql]
     
  15. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Код (Text):
    1. mysql> select * from `values`;
    2. +----+------------+--------+---------------------+---------+
    3. | id | account_id | value  | time_point          | user_id |
    4. +----+------------+--------+---------------------+---------+
    5. |  1 | 1          | 10.000 | 2010-03-01 00:00:00 | admin   |
    6. |  2 | 1          | 12.000 | 2010-04-01 14:00:00 | admin   |
    7. |  3 | 1          | 15.000 | 2010-04-02 14:48:25 | admin   |
    8. |  4 | 2          | 99.000 | 2010-04-01 15:14:02 | admin   |
    9. +----+------------+--------+---------------------+---------+
    запрос
    Код (Text):
    1. SELECT
    2. `values`.id,
    3. `values`.account_id,
    4. `values`.value,
    5. `values`.time_point,
    6. `values`.user_id
    7. FROM
    8. `values`
    9. GROUP BY
    10. `values`.account_id
    11. HAVING
    12. MAX(`values`.time_point) <  '2010-04-02 14:48:25'
    выбирает только
    Код (Text):
    1. +----+------------+--------+---------------------+---------+
    2. | id | account_id | value  | time_point          | user_id |
    3. +----+------------+--------+---------------------+---------+
    4. |  4 | 2          | 99.000 | 2010-04-01 15:14:02 | admin   |
    5. +----+------------+--------+---------------------+---------+
    6. 1 row in set (0.00 sec)
    И это, парни))) давайте вы договоритесь между собой, и придем к какому-нить результату. Ибо все с чем я до сих пор общался - простые запросы с одним джоином)
     
  16. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Simpliest
    У меня есть подозрение что
    Код (Text):
    1. HAVING MAX(time_point) < date
    отсечет все id, для которых есть значения более поздние чем $date.

    UPD:
    Похоже подозрения подтвердились...
     
  17. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Не-не, либо мы все договариваемся, либо только мы (которые вы) придем. =)))


    Простой запрос с одним джоином.

    и из этого тоже можно сделать простой запрос с одним джоином. =)
    [sql]select id, value from table as t
    where value in (select value as val from table where id=t.id and time_point<$date order by time_point desc limit 1)[/sql]
     
  18. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Я имел ввиду - более чем один результат общения для меня это совсем немного лучше чем ниодного;)

    и вложенным запросом :)

    Все хорошо, но ругается, что нельзя в вложенных запросах юзать limit
     
  19. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    ShamahN
    MAX(`values`.time_point) < '2010-04-02 14:48:25'
    Время хотя бы на 1с увеличь, или поставь <=
     
  20. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Понятно.
    Это обычно происходит, когда человек не умеет думать самостоятельно.
    Проблема выбора его напрягает категорически.
     
  21. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Ну так вложенный запрос тоже простой. =))

    Во-первых, я сказал что из этого тоже можно сделать. А во-вторых, он ругается не на все вложенные запросы, а только на некоторые.
     
  22. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Simpliest
    моя затупила :) простите сансей :) бью челом, - все работает... только как-то не правильно ((
    Код (Text):
    1. +----+------------+--------+---------------------+---------+
    2. | id | account_id | value  | time_point          | user_id |
    3. +----+------------+--------+---------------------+---------+
    4. |  1 | 1          | 10.000 | 2010-03-01 00:00:00 | admin   |
    5. |  4 | 2          | 99.000 | 2010-04-01 15:14:02 | admin   |
    6. +----+------------+--------+---------------------+---------+
    а должно быть
    Код (Text):
    1. +----+--------+---------------------+
    2. | id | value  | time_point          |
    3. +----+--------+---------------------+
    4. |  3 | 15.000 | 2010-04-02 14:48:25 |
    5. |  4 | 99.000 | 2010-04-01 15:14:02 |
    6. +----+--------+---------------------+
    Мы вибираем ближайшие к "2010-04-03 00:00:00" значения. данные - вот:

    Код (Text):
    1. +----+------------+--------+---------------------+---------+
    2. | id | account_id | value  | time_point          | user_id |
    3. +----+------------+--------+---------------------+---------+
    4. |  1 | 1          | 10.000 | 2010-03-01 00:00:00 | admin   |
    5. |  2 | 1          | 12.000 | 2010-04-01 14:00:00 | admin   |
    6. |  3 | 1          | 15.000 | 2010-04-02 14:48:25 | admin   |
    7. |  4 | 2          | 99.000 | 2010-04-01 15:14:02 | admin   |
    8. +----+------------+--------+---------------------+---------+
     
  23. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Вот пока что рабоспособный вариант, но какой-то он нетривиальный :)

    [sql] select `id`, `value`, `time_point` from `values` as t
    join
    (select account_id, max(`values`.time_point) as mtp from `values` where `values`.time_point<'2010-04-03 00:00:00' group by `account_id`) as actT
    on t.account_id=actT.account_id and t.time_point=actT.mtp[/sql]

    а если мне полученные данные по 'account_id' справа надо прилепить к какой-то таблице?)
     
  24. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Проверь на 2010-04-02 00:00:00

    Возьми все в скобки и цепляй. =))

    Грубо говоря что мы цепляем? Таблицы.
    А что нам возвращает запрос? Тоже таблицу.
    Так какая разница что цеплять запрос или таблицу?
     
  25. ShamahN

    ShamahN Активный пользователь

    С нами с:
    10 апр 2007
    Сообщения:
    1.449
    Симпатии:
    0
    Адрес:
    г.Волгодонск Роствской обл.
    Неправильно работает, почему-то(

    Но запрос:
    Отрабатывает идеально.
    Остановимся пока на нем (если конечно, не появится более красивого решения)

    Относительно этого запроса, как мне в список полей добавить еще 'account_id'. При добавлении ругается
    column 'account_id' in field list is ambiguous (ну и слово)