За чистый и ясный код!

Статьи на тему программирования под веб, используя PHP, MySQL, Jquery и многое другое

Итоги уходящего 2009

Декабрь30
Отличная поисковая оптимизация сайта с помощью уникального ресурса.

До конца года осталось почти сутки и половинка, я думаю самое время подвести итог уходящего 2009-го.

Начну по порядку с начала года

  1. В феврале первый раз с семьёй увидели свою новую квартиру
  2. Устроился на работу в хорошую фирму Стелла Системз, группа Диалог
  3. Начал изучать два фреймверка на PHP — ZendFramework и Kohana
  4. Начал писать различные статьи, понял что мне это нравится и …
  5. Открыл свой блог, правда времени пипец как мало на его развитие.
  6. Сыну уже почти год и семь месяцев, дочке будет 11.
  7. Начал делать ремонт в новой квартире — это просто ПИЗДЕЦ (извините, но на русском так будет понятней)
  8. Очень всерьез занялся подготовкой к получению Зенд сертификата

В общем год считаю очень хорошим.

ЗЫ Надеюсь в первом квартале переедем на новое место )) Люблю свою любимую половинку!

Статья просмотренна 29721 раз, зашло посетителей 8449

Dump MySQL, создание резервной копии БД

Декабрь12
Вашему вниманию качественная раскрутка сайта петербург.

Предисловие

Рано или поздно у всех стоит вопрос о создании копии БД. В сети есть очень много разных программ скриптов и прочего, но они хороши тогда, когда БД маленькая, ну как сейчас у нас, но если БД весит 1-2 ГГб, что делать???? Тут путь один, использовать родную командную утилиту mysqldump — тут столько букв, что я решил описать, по моему мнению, значимые параметры.

Синтаксис

В чем её преимущество — она быстрая, с кучей параметров, скорость её работы всегда будет выше, чем у phpmyadmin и им подобным.

shell> mysqldump [options] db_name [tables]
shell> mysqldump [options] --databases db_name1 [db_name2 db_name3...]
shell> mysqldump [options] --all-databases

где
[options] — это опции которые нужны для разных случаев, об этом ниже
db_name — база(ы) данных

Создание дампа

maxnag@svn:~/maxnag> mysqldump -uroot -ppassword maxnag_dev > maxnag_dev.sql

где -uroot — это параметр u означает юзер root, название этого юзера.

-ppassword — это параметр p означает пароль пользователя root

maxnag_dev — название БД, которая дампируетса.

> maxnag_dev.sql — знак больше говорит что весь поток дампа будет записан в файл maxnag_dev.sql по пути ~/maxnag, можно прописать любой путь.

Это самый простой способ получения дампа, для большинства случаев он подходит.

Восстановление дампа

maxnag@svn:~/maxnag> mysql -uroot -ppassword maxnag_dev < maxnag_dev.sql
или
maxnag@svn:~/maxnag> mysqldump -uroot -ppassword maxnag_dev < maxnag_dev.sql

параметры теже, команда восстанавливает БД из файла maxnag_dev.sql в БД maxnag_dev. Обратите внимание, что первая команда не выводит на экран содержимое дампа, а вторая выводит (я думаю это тоже регулируется в настройках)

Параметры и примеры

Теперь самое интересное. Это параметры и примеры.

Дамп только «скелета» таблиц

Для получение дампа только скелета таблиц используется параметр —no-data

maxnag@svn:~/maxnag> mysqldump -uroot -ppassword --no-data maxnag_dev > maxnag_dev.sql

Создание дампа нескольких БД

—databases, -B Параметр позволяет указать имена нескольких баз данных, для которых необходимо создать дамп.

maxnag@svn:~/maxnag> mysqldump -uroot -ppassword -B maxnag_dev mybloog > twoDB.sql

Создание дампа с исключением некоторых таблиц

—ignore-table=db_name.tbl_name Позволяет игнорировать таблицу tbl_name базы данных db_name при создании дампа. Если из дампа необходимо исключить несколько таблиц, необходимо использовать несколько параметров «—ignore-table», указывая по одной таблице в каждом из параметров.

Создание дампа с выборочными таблицами

maxnag@svn:~/maxnag> mysqldump -uroot -ppassword maxnag_dev --tables user user_data > page.sql

Обратите внимание, что сначала идет название таблицы, а потом перечисляться нужные таблицы.

Создание дампа триггеров

—triggers Создается дамп триггеров. Этот параметр включен по умолчанию. для его отключения следует использовать параметр —skip-triggers.

maxnag@svn:~/maxnag> mysqldump -uroot -ppassword test --tables user --triggers > user.sql

Кроме таблицы user в дампе содержится еще и триггеры, кусок дампа ниже

DELIMITER ;;
/*!50003 SET SESSION SQL_MODE="" */;;
/*!50003 CREATE */ /*!50017 DEFINER=`root`@`%` */ /*!50003 TRIGGER `test_user_pass2` BEFORE INSERT ON `user` FOR EACH ROW BEGIN
SET NEW.name = LEFT(NEW.name,1);
SET NEW.otch = LEFT(NEW.otch,1);
SET NEW.pass = md5(NEW.pass
END */;;

/*!50003 SET SESSION SQL_MODE="" */;;
/*!50003 CREATE */ /*!50017 DEFINER=`root`@`%` */ /*!50003 TRIGGER `test_user_pass` BEFORE UPDATE ON `user` FOR EACH ROW BEGIN
SET NEW.name = LEFT(NEW.name,1);
SET NEW.otch = LEFT(NEW.otch,1);
SET NEW.pass = md5(NEW.pass);
END */;;

DELIMITER ;

Создание дампа процедур и ф-ций

—routines, -R — с этим ключем идет их создание.

Создание дампа планировщика заданий

—events, -E с этим ключем идет их создание.

Создание дампа в виде XML

—xml, -X Представляет дамп базы данных в виде XML

maxnag@svn:~/maxnag> mysqldump -uroot -ppassword test --tables user -X> user.xml

вот часть содержимого

<table_data name="user">
    <row>
	<field name="id">1</field>
	<field name="fam">Нагайченко</field>
	<field name="name">М</field>
	<field name="otch">В</field>
	<field name="pass">5f4dcc3b5aa765d61d8327deb882cf99</field>
	<field name="login">maxnag</field>
    </row>
</table_data>

Создание дампа с разбиением его на части

Ну это нужно, если у вас дамп несколько ГГб и естественно вытащить такой, даже в архиве проблематично, то его можно разбить на части

maxnag@svn:~/maxnag> mysqldump -uroot -ppassword maxnag_dev | split -b 300K - maxnag.sql

Обратите внимаение, что -b, означает что мы указываем на какой объем следует делить, после этого параметра идет размер, он может быть

SIZE may have a multiplier suffix:<br>
b 512, kB 1000, K 1024, MB 1000*1000, M 1024*1024,<br>
GB 1000*1000*1000, G 1024*1024*1024, and so on for T, P, E, Z, Y.<br>

потом идет ТИРЕ, а не знак больше. И в файловой системе получается файл разбитый по указанному объему, для объединения используется команда линукса cat

Ну и напоследок, создание дампа с архивацией

maxnag@svn:~/maxnag> mysqldump -uroot -ppassword maxnag_dev | gzip > maxnag.sql.gz

B получаем дамп уже в архиве.

————————

Все параметры можно чередовать. Это наиболее часто используемые мной параметры.

Статья просмотренна 82027 раз, зашло посетителей 25672

Синхронизация БД с помощью триггеров (trigger MySQL)

Декабрь3

На одном из проектов, над которым я работаю по-ночам )), стала необходимость в перестройке БД (она была денормализована), приведение её к нормальным формам, а также переписыванию скриптов. Останавливать работающий проект низя — он коммерческий.

Как же быть? Точнее — необходимо было держать новую БД актуальной, чтобы когда, все будет готово и оттестировано просто сделать переключение на новую БД и радоваться своей работе.

Я принял такое решение, создать копию БД продакшена, поработать с ней, привести к нормализованному виду и потом синхронизировать. Так я и сделал.

Теперь пришло время подумать как же я буду синхронизировать БД старую и новую? Ведь хочется, что бы при добавлении/редактировании/удалении контента в старой БД, такие же действия происходили с ним в новой БД.

На помощь пришли триггеры MySQL, краткий экскурс что это такое я дал на странице своего блог Работа trigger (триггерами) в MySQL.

И так, есть таблица новостей, в ней есть поля:

mysql> DESCRIBE lib_news;
+---------------+--------------+------+-----+---------+----------------+
| Field         | Type         | Null | Key | Default | Extra          |
+---------------+--------------+------+-----+---------+----------------+
| id            | int(11)      | NO   | PRI | NULL    | auto_increment |
| dt            | int(11)      | NO   |     | 0       |                |
| title         | varchar(250) | NO   |     |         |                |
| descr         | text         | NO   |     | NULL    |                |
| text          | text         | NO   |     | NULL    |                |
| source        | varchar(250) | NO   |     |         |                |
| source_url    | varchar(250) | NO   |     |         |                |
| keywords      | text         | NO   |     | NULL    |                |
| img1          | varchar(20)  | NO   |     |         |                |
| img2          | varchar(20)  | NO   |     |         |                |
| img3          | varchar(20)  | NO   |     |         |                |
| img4          | varchar(20)  | NO   |     |         |                |
| img5          | varchar(20)  | NO   |     |         |                |
| first         | tinyint(1)   | NO   |     | 0       |                |
| fl            | tinyint(1)   | NO   | MUL | 0       |                |
| kol           | int(11)      | NO   |     | 0       |                |
| f_yandex      | tinyint(1)   | NO   |     | 0       |                |
| f_lenta       | tinyint(1)   | YES  |     | 0       |                |
| f_lenta_email | tinyint(1)   | YES  |     | 0       |                |
| comp_tp       | int(11)      | YES  |     | 0       |                |
+---------------+--------------+------+-----+---------+----------------+
20 rows in set (0.02 sec)

А вот поля из аналогичной таблицы в новой БД, разница в 2-х полях.

поле дата `dt` в старой это INT(11), в новой TIMESTAMP;
поле ИД компании comp_tp INT(11), в новой id_comp_tp SMALLINT(4);

mysql> DESCRIBE urbanus_lib_news;
+---------------+--------------+------+-----+-------------------+----------------+
| Field         | Type         | Null | Key | Default           | Extra          |
+---------------+--------------+------+-----+-------------------+----------------+
| id            | int(11)      | NO   | PRI | NULL              | auto_increment |
| id_comp_tp    | smallint(4)  | NO   |     | 0                 |                |
| dt            | timestamp    | NO   |     | CURRENT_TIMESTAMP |                |
| title         | varchar(250) | YES  |     | NULL              |                |
| descr         | text         | YES  |     | NULL              |                |
| text          | text         | YES  |     | NULL              |                |
| source        | varchar(250) | YES  |     | NULL              |                |
| source_url    | varchar(250) | YES  |     | NULL              |                |
| keywords      | text         | YES  |     | NULL              |                |
| img1          | varchar(20)  | YES  |     | NULL              |                |
| img2          | varchar(20)  | YES  |     | NULL              |                |
| img3          | varchar(20)  | YES  |     | NULL              |                |
| img4          | varchar(20)  | YES  |     | NULL              |                |
| img5          | varchar(20)  | YES  |     | NULL              |                |
| first         | tinyint(1)   | NO   |     | 0                 |                |
| fl            | tinyint(1)   | NO   | MUL | 0                 |                |
| kol           | int(11)      | NO   |     | 0                 |                |
| f_yandex      | tinyint(1)   | NO   |     | 0                 |                |
| f_lenta       | tinyint(1)   | NO   |     | 0                 |                |
| f_lenta_email | tinyint(1)   | NO   |     | 0                 |                |
+---------------+--------------+------+-----+-------------------+----------------+
20 rows in set (0.02 sec)

Получается, что при синхронизации таблиц, необходимо еще и приводить поля к нужному виду.

Ниже привожу триггеры которые и делают синхронизацию.

DROP TRIGGER IF EXISTS `lib_news_ai`;;
CREATE TRIGGER `lib_news_ai` AFTER INSERT ON `lib_news`
FOR EACH ROW
BEGIN
	INSERT INTO `newdb`.`new_lib_news` SET
		`id` = NEW.id, `dt` = FROM_UNIXTIME(NEW.`dt`), `id_comp_tp` = NEW.`comp_tp`, `title` = NEW.`title`,
		`descr` = NEW.`descr`, `text` = NEW.`text`, `source` = NEW.`source`, `source_url` = NEW.`source_url`,
		`keywords` = NEW.`keywords`, `img1` = NEW.`img1`, `img2` = NEW.`img2`, `img3` = NEW.`img3`,
		`img4` = NEW.`img4`, `img5` = NEW.`img5`, `first` = NEW.`first`, `fl` = NEW.`fl`, `kol` = NEW.`kol`,
		`f_yandex` = NEW.`f_yandex`, `f_lenta` = NEW.`f_lenta`, `f_lenta_email` = NEW.`f_lenta_email`
	ON DUPLICATE KEY UPDATE
		`id` = NEW.id, `dt` = FROM_UNIXTIME(NEW.`dt`), `id_comp_tp` = NEW.`comp_tp`, `title` = NEW.`title`,
		`descr` = NEW.`descr`, `text` = NEW.`text`, `source` = NEW.`source`, `source_url` = NEW.`source_url`,
		`keywords` = NEW.`keywords`, `img1` = NEW.`img1`, `img2` = NEW.`img2`, `img3` = NEW.`img3`,
		`img4` = NEW.`img4`, `img5` = NEW.`img5`, `first` = NEW.`first`, `fl` = NEW.`fl`, `kol` = NEW.`kol`,
		`f_yandex` = NEW.`f_yandex`, `f_lenta` = NEW.`f_lenta`, `f_lenta_email` = NEW.`f_lenta_email`;
END;;

DROP TRIGGER IF EXISTS `lib_news_au`;;
CREATE TRIGGER `lib_news_au` AFTER UPDATE ON `lib_news`
FOR EACH ROW
BEGIN
	INSERT INTO `newbd`.`new_lib_news` SET
		`id` = NEW.id, `dt` = FROM_UNIXTIME(NEW.`dt`), `id_comp_tp` = NEW.`comp_tp`, `title` = NEW.`title`,
		`descr` = NEW.`descr`, `text` = NEW.`text`, `source` = NEW.`source`, `source_url` = NEW.`source_url`,
		`keywords` = NEW.`keywords`, `img1` = NEW.`img1`, `img2` = NEW.`img2`, `img3` = NEW.`img3`,
		`img4` = NEW.`img4`, `img5` = NEW.`img5`, `first` = NEW.`first`, `fl` = NEW.`fl`, `kol` = NEW.`kol`,
		`f_yandex` = NEW.`f_yandex`, `f_lenta` = NEW.`f_lenta`, `f_lenta_email` = NEW.`f_lenta_email`
	ON DUPLICATE KEY UPDATE
		`id` = NEW.id, `dt` = FROM_UNIXTIME(NEW.`dt`), `id_comp_tp` = NEW.`comp_tp`, `title` = NEW.`title`,
		`descr` = NEW.`descr`, `text` = NEW.`text`, `source` = NEW.`source`, `source_url` = NEW.`source_url`,
		`keywords` = NEW.`keywords`, `img1` = NEW.`img1`, `img2` = NEW.`img2`, `img3` = NEW.`img3`,
		`img4` = NEW.`img4`, `img5` = NEW.`img5`, `first` = NEW.`first`, `fl` = NEW.`fl`, `kol` = NEW.`kol`,
		`f_yandex` = NEW.`f_yandex`, `f_lenta` = NEW.`f_lenta`, `f_lenta_email` = NEW.`f_lenta_email`;
END;;

DROP TRIGGER IF EXISTS `lib_news_ad`;;
CREATE TRIGGER `lib_news_ad` AFTER DELETE ON `lib_news`
FOR EACH ROW
BEGIN
	DELETE FROM `newbd`.`new_lib_news` WHERE `id` = OLD.id;
END;;

Как видно из св-в триггеров, любая новая запись в старой БД таблицы новостей будет записана в новую БД с изменениями которые необходимы. При редактировании также происходит обновление записей в 2-х БД. При удалении — удаление, соответственно.

Может возникнуть вопрос, почему я не использую простые запросы INSERT INTO или UPDATE. Ответ прост, вдруг по каким-то загадочным причинам в новой БД будет существовать запись с таким же ИД, который будет добавляться со старой БД, возникнет ошибка и ничего не будет, а используя конструкцию INSERT INTO ….. ON DUPLICATE KEY UPDATE (можно об этом почитать тут) я избегаю ошибки, даже если запись с таким же ИД есть, она будет обновлена. Или наоборот записи в новой БД нет, а в старой сделали исправление записи, следовательно эта запись добавится в новую БД.

Еще может возникнуть вопрос, а как же те записи, которые были добавлены в старую БД в момент реконструкции новой? Ну этот вопрос я  не буду рассматривать в данной статье, об этом я еще не думал, но скорее всего этим займутся или EVENT или PROCEDURE.

Всем удачи.

`newdb`.`new_lib_news`

Статья просмотренна 53843 раз, зашло посетителей 17279

Работа с trigger (триггерами) в MySQL

Декабрь2

Предисловие

Триггеры это особые процедуры которые срабатывают при изменении данных в таблицы операторами INSERT, UPDATE и DELETE.

Триггеры могут срабатывать как до BEFORE так и после AFTER изменения таблицы. Получается, что триггер может быть в 6 состояниях.

INSERT (BEFORE | AFTER)
UPDATE (BEFORE | AFTER)
DELETE (BEFORE | AFTER)

Что необходимо для работы

Cервер БД версии 5.0.2 и выше
привилегии на использование этой ф-ции (TRIGGER) начиная с версии 5.1.6, до этого было SUPER, но т.к. все локально используют пользователя root, то опасаться нечего

Добавление триггера

Для того чтобы понять работу триггера необходим пример.

Задание

Необходимо при добавлении записи в табл user, пароль преобразовывать в хеш md5(), также имя и отчество преобразовывать в инициалы.

Решение

mysql> DELIMITER //
mysql> CREATE TRIGGER `test_user_pass` BEFORE INSERT ON `test`.`user`
    -> FOR EACH ROW
    -> BEGIN
    ->  SET NEW.name = LEFT(NEW.name,1);
    ->  SET NEW.otch = LEFT(NEW.otch,1);
    ->  SET NEW.pass = md5(NEW.pass);
    -> END//
Query OK, 0 rows affected (0.09 sec)

mysql> DELIMITER ;

Теперь вставляем туда запись

mysql> INSERT  INTO `user` SET `fam`='Нагайченко', `name`='Максим', `otch` = 'Валерьевич', `pass` = 'password', `login` = 'maxnag';
Query OK, 1 row affected (0.00 sec)

Что теперь в таблице

mysql> SELECT * FROM `user`;
+----+-------------+------+------+----------------------------------+--------+
| id | fam         | name | otch | pass                             | login  |
+----+-------------+------+------+----------------------------------+--------+
|  1 | Нагайченко  | M    | В    | 5f4dcc3b5aa765d61d8327deb882cf99 | maxnag |
+----+-------------+------+------+----------------------------------+--------+

1 row in set (0.00 sec)

Как видно всего несколькими строчками можно убрать целые методы, которые мы использовали при регистрации нового пользователя. Теперь еще надо создать триггер на UPDATE таблицы, с таким же телом, чтобы пользователь не смог записать полное имя, отчество и пароль не в МД5();

Создание триггера на BEFORE UPDATE

mysql> DELIMITER //
mysql> CREATE TRIGGER `test_user_pass2` BEFORE UPDATE ON `test`.`user`
    -> FOR EACH ROW
    -> BEGIN
    ->  SET NEW.name = LEFT(NEW.name,1);
    ->  SET NEW.otch = LEFT(NEW.otch,1);
    ->  SET NEW.pass = md5(NEW.pass);
    -> END//
Query OK, 0 rows affected (0.09 sec)

mysql> DELIMITER ;

Обновление записи

mysql> UPDATE `user` SET `fam`='Иванов', `name`='Иван', `otch` = 'Иванович', `pass` = 'пароль', `login` = 'ivan' WHERE id=1;
Query OK, 1 row affected (0.00 sec)

Итог

mysql> SELECT * FROM `user`;
+----+-------------+------+------+----------------------------------+--------+
| id | fam         | name | otch | pass                             | login  |
+----+-------------+------+------+----------------------------------+--------+
|  1 | Иванов      | И    | И    | e242f36f4f95f12966da8fa2efd59992 | ivan   |
+----+-------------+------+------+----------------------------------+--------+

1 row in set (0.00 sec)

Могут возникнуть вопросы, что такое NEW в теле триггера,
NEW — для доступа к новым записям
OLD — для доступа к старым записям

Напимер, если я обновил фамилию, то новое значение мне доступно через NEW.fam, а к старому OLD.fam

Изменение триггера

А вот команды по изменению триггера я не нашел и был удивлен, почитал форумы, так и есть — её просто нет ((

Alter trigger

Удаление триггера

Для удаления триггера используется, как обычно оператор DROP, пример

DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name

где
schema_name — название БД,
trigger_name — название триггера

Список созданных триггеров

Показать триггер можно с помощью команды

SHOW TRIGGERS [{FROM | IN} db_name]
    [LIKE 'pattern' | WHERE expr]

Это полная часть команды, в основном пользуются командами:

SHOW TRIGGERS [FROM db_name] [LIKE 'pattern']
или
SHOW TRIGGERS

Это полная часть команды, в основном пользуются командами:

SHOW TRIGGERS [FROM db_name] [LIKE 'pattern']
или
SHOW TRIGGERS

Вот что мы увидем, когда выполним команду

mysql> SHOW TRIGGERS\G;
*************************** 1. row ***************************
             Trigger: test_user_pass
               Event: INSERT
               Table: user
           Statement: BEGIN
                          SET NEW.name = LEFT(NEW.name,1);
                          SET NEW.otch = LEFT(NEW.otch,1);
                          SET NEW.pass = md5(NEW.pass);
                      END
              Timing: BEFORE
             Created: NULL
            sql_mode: STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
             Definer: root@localhost
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_unicode_ci
1 row in set (0.01 sec)
Хороший ассортимент выбора книг, электроники, бытовой техники, посуды, подарки, сувениры и много другое Вы можете сделать на сайте компании E5.RU. Купить фильмы на dvd в фирменной упаковке и сделать хороший подарок родным и близким, Вы можете там же.

Статья просмотренна 178459 раз, зашло посетителей 79694

События (events) в MySQL (планировщик заданий аля CRON)

Ноябрь30

Предисловие

Наверное в 99% случаев если необходимо делать операции над данными в БД использовалась связка PHP и CRONа и в скрипте описывались все необходимые запросы. В MySQL 5.1.6 появился планировщик. Теперь можно не терзая указанную выше связку, если она не требует чего-то больше, что не умеет делать MySQL.

Для работы вам понадобится:

сервер БД 5.1.6 и выше; права пользователю на использование этой фичи.

Проверка работоспособности планировщика

Первое, что надо сделать — это удостоверится, что планировщик включен. Это можно сделать по команде

SHOW VARIABLES LIKE '%event%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | OFF   |
+-----------------+-------+

Получается он у меня выключен, ну что же можем включить:

SET GLOBAL event_scheduler = ON;

тем самым мы включили его до перезагрузки сервера!!! Что бы планировщик был постоянно включен необходимо в файле конфигурации поставить параметр: event_scheduler=1.

Теперь придумаем задание для того, что бы на его примере всё пояснить.

ЗАДАНИЕ

Например мы имеем таблицу users и нам каждый день в 00-00 необходимо выбирать всех, кто родился в этот день и записывать данные в табл users_dr (ФИО и пол). Можно конечно обойтись и простой выборкой по текущему дню, но если сайт с высокой нагрузкой, то делать выборку каждый раз это будет смерть БД.

Создание планировщика

Оператор планировщика имеет следующий синтаксис:

CREATE
    [DEFINER = { user | CURRENT_USER }]
    EVENT
    [IF NOT EXISTS]
    event_name
    ON SCHEDULE schedule
    [ON COMPLETION [NOT] PRESERVE]
    [ENABLE | DISABLE | DISABLE ON SLAVE]
    [COMMENT 'comment']
    DO sql_statement;

schedule:
    AT timestamp [+ INTERVAL interval] ...
  | EVERY interval
    [STARTS timestamp [+ INTERVAL interval] ...]
    [ENDS timestamp [+ INTERVAL interval] ...]

interval:
    quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
              WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
              DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

Много букв, но ничего, разберем на нашем примере.

DELIMITER ;;
DROP EVENT IF EXISTS `test_user_dr;;
CREATE EVENT `test_user_dr`
ON SCHEDULE EVERY 1 DAY STARTS '2009-07-19 00:00:00'
ON COMPLETION PRESERVE ENABLE
COMMENT 'таблица дней рождений'
DO
BEGIN
 DROP TABLE IF EXISTS `test`.`users_dr`;
 CREATE TABLE `test`.`users_dr`
   SELECT `fio`,`sex`
   FROM `test`.`users`
   WHERE `dr`=DATE_FORMAT(NOW(),"%d-%m")=DATE_FORMAT(`dr`,"%d-%m")
   ORDER BY `fio` ASC;
END;;
DELIMITER ;

Теперь разберем.

Т.к. в планировщике используется больше одного запроса, то эти запросы необходимо ограничивать директивами BEGIN и END, а для того, что бы MySQL не начал выполнять операции внутри планировщика, нам надо переопределить символ обозначающий конец запроса, по дефолту это ; Оператором DELIMITER ;; мы указываем, что теперь две косые есть конец запроса.

На всякий случай удаляем планировщик DROP EVENT IF EXISTS `test_user_dr` // Создаем новый планировщик `test_user_dr` с параметрами ON SCHEDULE EVERY 1 DAY STARTS ‘2009-07-19 00:00:00’, означает каждый в 00-00-00 начиная с указанной даты, параметр DAY — интервал, может принимать и другие параметры, о них написано выше. Далее говорим ON COMPLETION PRESERVE ENABLE — включаем этот планировщик и если он завершиться ОКОНЧАТЕЛЬНО, то его из памяти не удаляем. Наш планировщик никогда не завершается, т.к. нет директивы ENDS timestamp, но если бы он была и было написано ON COMPLETION NOT PRESERVE, то всё задание удалилось. С комментарием, думаю, все понятно. Далее после слов DO BEGIN идут запросы, которые будут выполняться планировщиком и заканчивает директивой END.

Теперь планировщик будет каждый день начиная с 19 июля 2009 года в полночь делать таблицу пользователей у которых ДР в текущий день.

Удаление планировщика

Тут все просто, используем оператор

DROP EVENT [IF EXISTS] event_name</pre>
В нашем случае
<pre lang="sql">DROP EVENT IF EXISTS `test_user_dr`;</pre>
<h2>Изменение планировщика</h2>
<pre lang="sql">ALTER
    [DEFINER = { user | CURRENT_USER }]
    EVENT event_name
    [ON SCHEDULE schedule]
    [ON COMPLETION [NOT] PRESERVE]
    [RENAME TO new_event_name]
    [ENABLE | DISABLE | DISABLE ON SLAVE]
    [COMMENT 'comment']
    [DO sql_statement]

Например надо изменить время срабатывания, ну например чтобы таблицы ДР обновлялась 2 раза в сутки, тогда следует написать

ALTER EVENT `test_user_dr` ON SCHEDULE EVERY 12 HOUR;

Список планировщиков

Список заданий можно посмотреть 2-мя способами:

1-й покажет все данные по всем планировщикам для БД test

SHOW EVENTS FROM `test`\G;
*************************** 1. row ***************************
                  Db: test
                Name: test_user_dr
             Definer: root@localhost
           Time zone: SYSTEM
                Type: RECURRING
          Execute at: NULL
      Interval value: 12
      Interval field: HOUR
              Starts: 2009-07-19 00:00:00
                Ends: NULL
              Status: ENABLED
          Originator: 0
character_set_client: cp1251
collation_connection: cp1251_general_ci
  Database Collation: cp1251_general_ci
1 row in set (0.00 sec)

2-й Показывает полностью данные для указанного задания

SHOW CREATE EVENT `test_user_dr`\G;
*************************** 1. row ***************************
               Event: test_user_dr
            sql_mode: STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
           time_zone: SYSTEM
        Create Event: CREATE EVENT `test_user_dr` и весь текст планировщика...
character_set_client: cp1251
collation_connection: cp1251_general_ci
  Database Collation: cp1251_general_ci
1 row in set (0.00 sec)

Ну вроде все. Если есть вопросы пишите, буду отвечать.

Ссылки

Официальное руководство

Статья просмотренна 81643 раз, зашло посетителей 28498

Список локалей

Ноябрь28
Компьютеры для юридических лиц, фирм и компаний от adelsy.ru, заходи выбирай как игровой компьютер, так и для бизнеса.

Всем привет.

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

Команда для просмотра локалей на Вашем сервере, кто не знает:

maxnag@nagaychenko:~> cd /usr/lib/locale/
maxnag@nagaychenko:/usr/lib/locale> ls

А вот и список:

aa_DJ            es_BO.utf8           mn_MN
aa_DJ.utf8       es_CL                mn_MN.utf8
aa_ER            es_CL.utf8           mr_IN
aa_ER@saaho      es_CO                mr_IN.utf8
aa_ER.utf8       es_CO.utf8           ms_MY
aa_ET            es_CR                ms_MY.utf8
aa_ET.utf8       es_CR.utf8           mt_MT
af_ZA            es_DO                mt_MT.utf8
af_ZA.utf8       es_DO.utf8           nb_NO
am_ET            es_EC                nb_NO.utf8
am_ET.utf8       es_EC.utf8           nds_DE
an_ES            es_ES                nds_NL
an_ES.utf8       es_ES@euro           ne_NP
ar_AE            es_ES.utf8           ne_NP.utf8
ar_AE.utf8       es_GT                nl_BE
ar_BH            es_GT.utf8           nl_BE@euro
ar_BH.utf8       es_HN                nl_BE.utf8
ar_DZ            es_HN.utf8           nl_NL
ar_DZ.utf8       es_MX                nl_NL@euro
ar_EG            es_MX.utf8           nl_NL.utf8
ar_EG.utf8       es_NI                nn_NO
ar_IN            es_NI.utf8           nn_NO.utf8
ar_IN.utf8       es_PA                no_NO
ar_IQ            es_PA.utf8           no_NO.utf8
ar_IQ.utf8       es_PE                nr_ZA
ar_JO            es_PE.utf8           nso_ZA
ar_JO.utf8       es_PR                oc_FR
ar_KW            es_PR.utf8           oc_FR.utf8
ar_KW.utf8       es_PY                om_ET
ar_LB            es_PY.utf8           om_ET.utf8
ar_LB.utf8       es_SV                om_KE
ar_LY            es_SV.utf8           om_KE.utf8
ar_LY.utf8       es_US                or_IN
ar_MA            es_US.utf8           pa_IN
ar_MA.utf8       es_UY                pa_IN.utf8
ar_OM            es_UY.utf8           pap_AN
ar_OM.utf8       es_VE                pa_PK
ar_QA            es_VE.utf8           pl_PL
ar_QA.utf8       et_EE                pl_PL.utf8
ar_SA            et_EE.iso885915      pt_BR
ar_SA.utf8       et_EE.utf8           pt_BR.utf8
ar_SD            eu_ES                pt_PT
ar_SD.utf8       eu_ES@euro           pt_PT@euro
ar_SY            eu_ES.utf8           pt_PT.utf8
ar_SY.utf8       fa_IR                ro_RO
ar_TN            fa_IR.utf8           ro_RO.utf8
ar_TN.utf8       fi_FI                ru_RU
ar_YE            fi_FI@euro           ru_RU.koi8r
ar_YE.utf8       fi_FI.utf8           ru_RU.utf8
as_IN.utf8       fil_PH               ru_UA
ast_ES           fo_FO                ru_UA.utf8
ast_ES.utf8      fo_FO.utf8           rw_RW
az_AZ.utf8       fr_BE                sa_IN
be_BY            fr_BE@euro           sc_IT
be_BY@latin      fr_BE.utf8           se_NO
be_BY.utf8       fr_CA                se_NO.utf8
ber_DZ           fr_CA.utf8           shs_CA
ber_MA           fr_CH                sh_YU
bg_BG            fr_CH.utf8           sh_YU.utf8
bg_BG.utf8       fr_FR                sid_ET
bn_BD            fr_FR@euro           sid_ET.utf8
bn_BD.utf8       fr_FR.utf8           si_LK
bn_IN            fr_LU                sk_SK
bn_IN.utf8       fr_LU@euro           sk_SK.utf8
bo_CN            fr_LU.utf8           sl_SI
bo_IN            fur_IT               sl_SI.utf8
br_FR            fy_DE                so_DJ
br_FR@euro       fy_NL                so_DJ.utf8
br_FR.utf8       ga_IE                so_ET
bs_BA            ga_IE@euro           so_ET.utf8
bs_BA.utf8       ga_IE.utf8           so_KE
byn_ER           gd_GB                so_KE.utf8
byn_ER.utf8      gd_GB.utf8           so_SO
ca_AD            gez_ER               so_SO.utf8
ca_AD.utf8       gez_ER@abegede       sq_AL
ca_ES            gez_ET               sq_AL.utf8
ca_ES@euro       gez_ET@abegede       sr_ME
ca_ES.utf8       gl_ES                sr_RS
ca_FR            gl_ES@euro           sr_RS@latin
ca_FR.utf8       gl_ES.utf8           ss_ZA
ca_IT            gu_IN                st_ZA
ca_IT.utf8       gv_GB                st_ZA.utf8
crh_UA           gv_GB.utf8           sv_FI
csb_PL           ha_NG                sv_FI@euro
cs_CZ            he_IL                sv_FI.utf8
cs_CZ.utf8       he_IL.utf8           sv_SE
cy_GB            hi_IN                sv_SE.iso885915
cy_GB.utf8       hi_IN.utf8           sv_SE.utf8
da_DK            hr_HR                ta_IN
da_DK.utf8       hr_HR.utf8           ta_IN.utf8
de_AT            hsb_DE               te_IN
de_AT@euro       hsb_DE.utf8          te_IN.utf8
de_AT.utf8       hu_HU                tg_TJ
de_BE            hu_HU.utf8           tg_TJ.utf8
de_BE@euro       hy_AM                th_TH
de_BE.utf8       hy_AM.armscii8       th_TH.utf8
de_CH            id_ID                ti_ER
de_CH.utf8       id_ID.utf8           ti_ER.utf8
de_DE            ig_NG                ti_ET
de_DE@euro       ik_CA                ti_ET.utf8
de_DE.utf8       is_IS                tig_ER
de_LU            is_IS.utf8           tig_ER.utf8
de_LU@euro       it_CH                tk_TM
de_LU.utf8       it_CH.utf8           tl_PH
dz_BT            it_IT                tl_PH.utf8
el_CY            it_IT@euro           tn_ZA
el_CY.utf8       it_IT.utf8           tr_CY
el_GR            iu_CA                tr_CY.utf8
el_GR.utf8       iw_IL                tr_TR
en_AU            iw_IL.utf8           tr_TR.utf8
en_AU.utf8       ja_JP.eucjp          ts_ZA
en_BE            ja_JP.shiftjisx0213  tt_RU@iqtelif.UTF-8
en_BE@euro       ja_JP.sjis           tt_RU.utf8
en_BE.utf8       ja_JP.utf8           ug_CN
en_BW            ka_GE                uk_UA
en_BW.utf8       ka_GE.utf8           uk_UA.utf8
en_CA            kk_KZ                ur_PK
en_CA.utf8       kk_KZ.utf8           ur_PK.utf8
en_DK            kl_GL                uz_UZ
en_DK.utf8       kl_GL.utf8           uz_UZ@cyrillic
en_GB            km_KH                ve_ZA
en_GB.iso885915  kn_IN                vi_VN
en_GB.utf8       ko_KR.euckr          vi_VN.tcvn
en_HK            ko_KR.utf8           wa_BE
en_HK.utf8       ku_TR                wa_BE@euro
en_IE            ku_TR.utf8           wa_BE.utf8
en_IE@euro       kw_GB                wo_SN
en_IE.utf8       kw_GB.utf8           xh_ZA
en_IN            ky_KG                xh_ZA.utf8
en_IN.utf8       lg_UG                yi_US
en_NG            lg_UG.utf8           yi_US.utf8
en_NZ            li_BE                yo_NG
en_NZ.utf8       li_NL                zh_CN
en_PH            lo_LA                zh_CN.gb18030
en_PH.utf8       lt_LT                zh_CN.gbk
en_SG            lt_LT.utf8           zh_CN.utf8
en_SG.utf8       lv_LV                zh_HK
en_US            lv_LV.utf8           zh_HK.utf8
en_US.iso885915  mai_IN               zh_SG
en_US.utf8       mg_MG                zh_SG.gbk
en_ZA            mg_MG.utf8           zh_SG.utf8
en_ZA.utf8       mi_NZ                zh_TW
en_ZW            mi_NZ.utf8           zh_TW.euctw
en_ZW.utf8       mk_MK                zh_TW.utf8
es_AR            mk_MK.utf8           zu_ZA
es_AR.utf8       ml_IN                zu_ZA.utf8
es_BO            ml_IN.utf8

Всем удачи, Максим.

Статья просмотренна 44700 раз, зашло посетителей 13858

Парсинг CSV файлов на PHP

Ноябрь28

В данной статье речь пойдет о распознавании  формата CSV.

Что такое формат данных CSV, пояснять не буду, прочитайте об этом на http://ru.wikipedia.org/wiki/CSV.

И так, у меня был исходный файл в CSV формате, с кодировкой UTF-8, необходимо было его разобрать, для последующего заноса в базу данных.

Небольшой фрагмент этого файла

Имя;Фамилия;Мыло;Разное
Максим;Нагайченко;max_nag[at]meta.ua;программист
"?Мария";"????µ";intik_79[at]mail.ru;
;;some@email.com

Как видно здесь встречаются кириллица, латиница, умляуты (расширенная латиница).

Для парсинг я воспользовался стандартной ф-цией PHP — fgetcsv.

При разборе на виндовс машине вообще никаких проблем не возникло, все было разобрано, разложено — в общем все как надо, осталось только занести в БД.

При разборе этого файла на линукс машине возникли проблемы — кириллица вообще не хотела распознаваться, если она не была обрамлена — кавычкой («). Решение нашлось за 30 минут и выпитой чашкой чая.

Оказывается, необходимо указывать корректную локаль при работе с данной ф-цией, об этоя я прочитал в комментариях к указанной выше ф-ции.

setlocale(LC_ALL, 'ru_RU.UTF-8');

Если у вас в проекте используется несколько языков интерфейса, то при переключении, не забудьте переключить локаль. Особенно это важно, если для перевода интерфейса используется ф-ция gettext().

Всем удачи, Максим.

Статья просмотренна 73140 раз, зашло посетителей 26433

Переменные переменных в PHP

Ноябрь26

В этой статье речь пойдет о так называемых — «переменные переменных«.

Что же это??? Наверняка каждый программист php сталкивался с переменными, которые имеют нестандартное название, точнее нестандартное создание переменных ($$ и тд), вот примеры

$$someVariable

${'rrr'}

$f()

Все это так называемые — «переменные переменных«. Это значение переменной, которое может стать самой переменной.

Разберем как они работают. Перед Вами небольшой код в котором я постарался собрать все примеры.

<?php
function myFunc()
{
echo 'Hello&lt;br&gt;';
}

$myVariable = 'myFunc';

$myVariable();
/*----------------------------------------*/
$someVar = 'hello';

$$someVar = 'Auf Wiedersehen&lt;br&gt;';

echo $hello;
/*----------------------------------------*/
$втораяПеременная = '123';

$$втораяПеременная = 'apple';

echo ${'123'};
?>

На экране будет выведено:

Hello
Auf Wiedersehen
apple

Я объясню на одном примере :

function myFunc()
{
echo 'Hello<br>';
}

$myVariable = 'myFunc';
$myVariable();

Тут видно, что создана ф-ция с названием myFunc которая выведет слово Hello<br>.  Мы конечно можем просто вызвать ф-цию через обращение к ней myFunc(); , но можно воспользоваться и другой конструкцией. Создать переменную (любую) потом присвоить ей значение — это само название ф-ции. И применив к переменной скобки () мы вызовем на исполнение данную ф-цию.

Многие могут сказать, мол чё за маразм, нафиг надо, чего путаете, но поверте, когда будет большой опыт, то будут ситуации в которых эти конструкции сильно пригодятся.

В последнем примере, как Вы думаете, почему я применил такой подход ${‘123’}; зачем эти фигурные скобки???? Ответ — т.к переменная не может начинаться с цифры, а $втораяПеременная = ‘123’; , точнее значение переменной, которое потом преобразуется в переменную, именно цифра, то для экранирования, обхода этого ограничения, используется ${‘someVar’} конструкция.

И еще, название переменных может быть не только на латинице, как пишется в некоторых книгах [a-zA-Z_0-9], но даже и иероглифы $? = ‘123’; (только если кодировка файла UTF-8, естественно).

Полезная ссылка:

http://www.php.net/manual/en/language.variables.php

Всем удачи, Максим.

Статья просмотренна 44934 раз, зашло посетителей 11767

  

Облако тегов

cli csv dump events form Kohana locale models MySQL mysqldump orm PHP tools trigger validate газ газовый счетчик итоги кеширование переменные

Облако тегов плагина WP Cumulus для WordPress требует для просмотра Flash Player 9 или выше.

Я на твиттере!

  • у твиттера тоже бывают перерывы...

Календарь

Апрель 2024
Пн Вт Ср Чт Пт Сб Вс
« Июл    
1234567
891011121314
15161718192021
22232425262728
2930  

Сейчас на сайте