За последние 24 часа нас посетили 22410 программистов и 997 роботов. Сейчас ищут 677 программистов ...

репозитарий полезных SQL запросов/процедур/функций

Тема в разделе "MySQL", создана пользователем Psih, 9 мар 2007.

  1. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Предлагаю в данный топик складывать полезные сложные SQL запросы/процедуры/функции, дабы каждый из нас не создавал собственный велосипед, а мог бы взять хорошее, быстрое, удобное и работающее решение и применить его.

    Первым внесу свою лепту. Это процедураб которая вычисляет, сколько осталось дней до дня рождения человека (на основе даты его рождения) и возраст человека. Учитываються такие факторы как високосный год. Тип поля должен быть DATETIME или любого другого схожего типа.
    prf_age - возраст пользователя (integer)
    prf_days_left - кол-во дней до дня рождения. Если равно 0, значит у человека день рождение. У процедуры 1 параметр, который принимает ID пользователя, которому надо обновить данные. Если он равен NULL, то пересчитывает для всей таблицы.

    Запускать ежедневно в полночь.
    Код (Text):
    1. CREATE PROCEDURE `check_birthday`(in_prf_id INTEGER(11))
    2.     NOT DETERMINISTIC
    3.     SQL SECURITY DEFINER
    4.     COMMENT ''
    5. BEGIN
    6.   DECLARE days_in_year INTEGER DEFAULT IF(DATE_FORMAT(CURDATE(), "%m%d") = "0229", 365, IF(IFNULL(DATE(CONCAT(IF(MONTH(CURDATE()) > 2, YEAR(CURDATE())+1, YEAR(CURDATE())), "-02-29")), 0) = 0, 365, 366));
    7.  
    8.   UPDATE profiles SET
    9.   prf_age = TIMESTAMPDIFF(YEAR, prf_birthday, NOW()),
    10.   prf_days_left =  IF((@days := ABS(TIMESTAMPDIFF(DAY, prf_birthday + INTERVAL TIMESTAMPDIFF(YEAR, prf_birthday, CURDATE())+1 YEAR,  CURDATE()))) = days_in_year, 0, @days)
    11.   WHERE IF(in_prf_id IS NULL, TRUE, FALSE) OR prf_id=in_prf_id;
    12. END;
    Разрабатывалось и тестировалось на реальном проэкте, на таблице в 24 000 записей, объёмом 5.5 мегабайт. По сравнению с приведущими вариантами просто молния :) Выслушаю конструктивные предложения, которые улучшат быстродействие :)
     
  2. AmiD

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

    С нами с:
    16 янв 2007
    Сообщения:
    99
    Симпатии:
    0
    Адрес:
    Томсква
    Это как ??? :shock:
     
  3. Luge

    Luge Старожил

    С нами с:
    2 фев 2007
    Сообщения:
    4.680
    Симпатии:
    1
    Адрес:
    Минск
    AmiD
    cron и т.д.
     
  4. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Да, ветку было бы неплохо закрепить.
     
  5. AmiD

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

    С нами с:
    16 янв 2007
    Сообщения:
    99
    Симпатии:
    0
    Адрес:
    Томсква
    Luge
    а где поподробней почитать ? или в гугль ?
     
  6. vb

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

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    вижу 1 процедуру совершенно индивидуальную.
    вижу офтоп.
    поводов закреплять ветку не вижу.
     
  7. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    1 - подставить вместо двух полей свои поля народ я думаю в состоянии.. или мне вместо полей назвать table и birthday_field и age_field ?
    2 - зачисти оффотп, пускай здесь будет только то что нужно, сообщение я могу подправить первое, если надо. Индивидуальность только в том, что там есть название таблицы и полей. Но это готовое решение, просто подставте поля, которые нужно вам, вот и всё.
     
  8. Anonymous

    Anonymous Guest

    угнать чужой =)
     
  9. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Именно, ибо я например 3 раза переписывал, потому что тут народ реализовывал это в таком виде, что волосы шевелились не тока на голове (куча ифов, конкатов, date_format, substr и.т.д., убил бы, будь я главным программером), вообщем потрачено на это много времени, а полезна функция будет в любом месте, где надо понять, сколько человеку лет и сколько ему осталось до дня рождения.
    P.S. Я создавал топик с целью репозитария примеров, готовых решений, но это не значит что сделал copy/paste и будет работать. Это SQL, поля в базе у всех по разному будут в любом случае называться. Кому надо, подправят или выкинут лишнее.
     
  10. Anonymous

    Anonymous Guest

    Ага. Если этого ежа, взять, и бережно держа... впрочем, он наверно сдохнет, но идея хороша!
    Ладно, оффтоп к утру почищу, Репозиторий... согласен, готовые решения можно где нить складывать. Тоже обдумаю.
     
  11. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    Psih, ужас какой... не проще ли сразу хранить в базе timestamp и манипуляци производить на php при выводе?
     
  12. Mavir

    Mavir Guest

    dark-demon, как выбирать пользователей у которых до дня рождения осталось меньше, например, двух недель?
     
  13. vb

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

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Mavir, гы гы гы :)

    Доктор, я написал функцию сложения two_plus_two(), она умеет складывать 2+2, для сложения 2+3 используйте функцию two_plus_three()
    Что значит ругается? Работает то только в mysql 5.x, думать надо было :)
    А и имя таблицы надо было поменять, и еще поля заменить - она знак плюс читает там где то :)

    Много видел кривых и непонятных кодов откоторых ругался, вот толи дело мой :)
     
  14. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    Mavir, раз в год вычислять дату дня рождения в следующем году :)
     
  15. vb

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

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    dark-demon, +1
    Mavir, блин я не внимательно прочитал думал ты задаешь вопрос на первый пост топика :) но все равно гы гы гы :)
     
  16. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Нет, не проще, потому что:
    Так ты знаешь сколько у человека до дня рождения + ничего не надо вычислять на ходу (а вычисления сам видишь какие, они неплохо грузят сервак) - выигрываешь в производительности солидно.
    Второе - у меня есть задача выводить пользователей, у которых 30 и менее дней до дня рождения.
    3 - тут же считается возраст пользователя. Если у него сегодня день рождение, то соответственно его возраст тоже обновится.
    4 - в базе КУДА проще работать с датами, настолько же прозрачно, насколько это прозрачно с числами. В PHP ты бы замучался реализовывать это + у тебя бы это сожрало хорошее кол-во CPU time. А у меня не домашняя страничка, там 1 неоптимизированный запрос или PHP функция может весь сайт положить, потому что даже небольшая задержка помноженная на кол-во запросов к серверу приводит к хорошим тормозам.
    5 - Так что учите SQL, он важнее чем PHP даже для хорошего WEB программера :p
     
  17. vb

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

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Psih, это мы не с тобой о форматах ханения даты спорили?

    Последний твой пост сплошное противоречее :).
     
  18. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Вот уж вычислить кол-во дней/лет и.т.д. между двумя датами, с учётом високосных лет и.т.д., я думаю будет сложновато и весьма неэфективно на PHP :) Зачем это делать на PHP, когда SQL справиться с этим лучше и куда быстрее :)

    Хотя бы "дата рождения + кол-во лет пользователя" и получить правильную дату, с учётом високосного (и не одного) года :) Вам нужен этот гемморой? :)

    P.S. У меня оптимизированный запрос + выполняется раз в сутки в 12 ночи, когда народу на сайте не очень много. Отрабатываает он быстро и совсем незаметно. Я даже представить не могу реализацию этого на PHP - насколько бы это было громоздко и медленно, да ещё и на каждого пользователя обработать надо данные. А что вы будете делать когда пользователей будет 100-200 тысячь? Тоже выбирать в PHP результат и гонять этот мега-масив (одна выборка займёт в разы больше времени, чем отработка запроса в недрах SQL сервера)? :)
     
  19. vb

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

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Psih, извиняюсь за такой вопрос... тебе известно о функциях strtotime(), date()?
    Скорее всего это ошибочное мнение :).

    PHP:
    1. <?$time = strtotime("+10 year", $time_brithday);?>
    и в чем тут гемор?
     
  20. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Элементарно ватсон, я даже не буду объяснять, просто приведу первый же комент в официальном мануале
    Хотя бы уже это. Не забывайте, мы работаем не с текущими датами в пределах года или двух, а с куда более широкими диапазонами, так что UNIX TIMESTAMP тут просто не годиться уважаемый.
    Да, в жтом случае решение есть, но немного притянутое зауши, хоть, соглашусь, и элегантное. Но опять же, попадись нам дата меньше чем 1970-01-01 - мы в пролёте.
    Следующий же ответ выявляет проблему, решение которой..
    Снова SQL.
    И.т.д... Куча нюансов, хаков и.т.д., + куда меньше функций для манипулирования датами, всё надо писать самому. Я даже не хочу вдаваться в подробности проблемы, потому что там просто куча условий, нюансов, неудобностей и.т.д.
     
  21. vb

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

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    это называется не стандартной задачей, так же как не стоит забывать что существуют года до нашей эры :)
    И тут тип datetime так же бессилен.

    В большинстве решаемых задач даты от эпохи юникса достаточно.
    Так же как большинству задач хватает нашей эры :).
    так что не забывайте люди живут ... давно :)

    Если Вы скажите, что ваша процедура не посчитает сколько лет человеку родившимуся в 4013 году до нашей эры, мое сердце будет разбито :p
     
  22. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    vb
    Уж извините, база данных не поддерживает такие даты, да и пример ваш выдуман уж сильно :) Покажите мне базу данных которая поддерживает даты до нашей эры :) MySQL точно не умеет, он умеет только
     
  23. vb

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

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Я же не базу придумываю, а задачу. Это в качестве примера о не стандартных задачах. Так же для большинства решений достаточно даты в формате секунд от начала эпохи юникса.

    p.s. не могли бы вы НЕ переписывать дописывать полностью свои посты. А то как то тупо получается вроде уже ответил на вопрос, а пост уже переписан пару раз.
     
  24. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    vb я от вас такой прыти не ожидал просто :)
     
  25. vb

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

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Psih, да бывает и мы спускаемся с небес на землю посмотреть что люди говорят :) ШУТКА :)